LeetCode 283. 移动零:从辅助数组到双指针原地算法

题目描述

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

注意:

  1. 必须在不复制数组 的情况下原地对数组进行操作。

  2. 进阶:尽量减少完成的交互次数。

解法一:辅助数组法(不符合原地要求)

这是最直观的解法,思路是创建一个新的数组,将非零元素依次填入,剩余位置补零,最后再拷贝回原数组。

代码:

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int length1 = nums.size();
        // 创建了辅助数组 a,空间复杂度 O(N)
        vector<int> a(nums.size());
        int num = 0;
        
        // 第一次遍历:将非零元素放入辅助数组
        for(int i = 0; i < nums.size(); i++) {
            if(nums[i] != 0) {
                a[num] = nums[i];
                num++;
            }
        }
        
        // 第二次遍历:将辅助数组剩余位置补零
        for(int i = num; i < length1; i++) {
            a[i] = 0;
        }
        
        // 第三次遍历:将辅助数组拷贝回原数组
        for(int i = 0; i < nums.size(); i++) {
            nums[i] = a[i];
        }
        return;
    }
};

复杂度分析:

时间复杂度:O(N)。进行了三次遍历。

空间复杂度 :O(N)。开辟了与原数组等大的辅助空间 a。

不足 :题目明确要求原地操作(In-place),因此该解法虽然逻辑正确,但空间复杂度不符合题目进阶要求,面试中通常会被要求优化。

解法二:双指针法(最优解)

为了满足"原地"且"减少操作次数"的要求,我们可以使用双指针(快慢指针)。

核心思想

使用两个指针:

slow:指向当前已经处理好的非零序列的末尾(即下一个非零元素应该放置的位置)。

fast:遍历整个数组。

算法流程:

  1. fast 从左向右遍历。

  2. 当 nums[fast] != 0 时,交换 nums[slow] 和 nums[fast],然后 slow 向前移动一位。

  3. 当 nums[fast] == 0 时,不做处理,fast 继续前进。

这样,slow 左边始终是非零元素,且相对顺序保持不变;slow 到 fast 之间全是 0。通过交换,直接将 0 换到了后面。

正确代码实现

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slow = 0;
        int n = nums.size();
        
        // fast 为快指针,遍历数组
        for (int fast = 0; fast < n; fast++) {
            // 当遇到非零元素时,与 slow 指针位置交换
            if (nums[fast] != 0) {
                swap(nums[slow], nums[fast]);
                slow++;
            }
        }
    }
};

复杂度分析:

时间复杂度:O(N)。只需遍历一次数组。

空间复杂度:O(1)。仅使用了常数个变量,满足原地操作要求。

操作次数:每个非零元素最多被交换一次,相比辅助数组法减少了赋值操作。

总结与对比

维度 辅助数组法 双指针法 (最优解)
空间复杂度 O(N) - 需要额外数组 O(1) - 原地操作
时间复杂度 O(N) - 遍历3次 O(N) - 遍历1次
相关推荐
sinat_286945191 小时前
大模型推理:部署方式与性能优化思路
人工智能·算法·缓存·chatgpt·性能优化
在所不辞兄1 小时前
【零基础学智能仿真-42】二维随机有限元实战——把随机材料场赋给网格单元
人工智能·深度学习·算法·机器学习·工程仿真
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】C++ ChatSDK使用手册
开发语言·网络·c++·人工智能·学习·大模型
罗湖老棍子5 小时前
Biorhythms(信息学奥赛一本通- P1639)
算法·数论·裴蜀定理·扩展欧几里得·扩展中国剩余定理
程序喵大人10 小时前
【C++入门】编译链接模型 - 01 一个 C++ 程序是怎样变成可执行文件的
开发语言·c++·编译链接模型
奋发向前wcx10 小时前
CSP-J复赛模拟赛4 王晨旭补题 2026.10.5
算法
by2099911 小时前
vector 的模拟实现:扩容与边界的详细阐述(下)
c++·经验分享·vector·动态数组
念何架构之路13 小时前
zap采样器与性能优化内幕
算法·性能优化·哈希算法
晒太羊的猫14 小时前
hot100动态规划刷题
算法·动态规划