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次
相关推荐
一去不复返的通信er7 小时前
力扣-图论-岛屿数量
算法·leetcode·图论
青瓦梦滋7 小时前
WebSocket协议
linux·服务器·网络·c++·websocket·网络协议·http
程序 代码狂人10 小时前
切片表与分区表的区别(数据开发面试版)
java·大数据·开发语言·数据仓库·算法
HDU-Dade10 小时前
【校招笔试真题】简要介绍 Self-Attention 的前沿算法
人工智能·算法
Xin77011 小时前
LeetCode 79. 单词搜索(DFS 回溯法)
leetcode
小郎君65812 小时前
Vue keep-alive 切标签后滚动位置回顶?因为 onDeactivated 里读到的 scrollTop 是 0
算法
CodeYp201913 小时前
第15讲:二叉搜索树
开发语言·c++·二叉搜索树
邵奈一13 小时前
GPT-6.1 Terra速度是Sol的3倍,价格减半
算法
RaaS10013 小时前
Node.js Brotli RCE 漏洞自查指南:fetch、undici、axios 都在影响面,三分钟确认你的版本
人工智能·深度学习·算法