双指针1:移动零

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

<<Git>><<MySQL>>

🌟心向往之行必能至

题目描述

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。注意:必须在不复制数组的情况下原地对数组进行操作。

示例

  • 输入:nums = [0,1,0,3,12]
  • 输出:[1,3,12,0,0]

方法一:双指针交换法

思路

我们可以用一个指针 left 来记录当前非零元素应该放置的位置,然后遍历数组。当遇到非零元素时,就将它与 left 位置的元素交换,并让 left 指针右移。这样可以保证 left 指针之前的所有元素都是非零的,且保持了原有顺序。

代码实现

cpp

复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int left = 0;
        for (auto& x : nums) {
            if (x != 0) {
                swap(x, nums[left]);
                left++;
            }
        }
    }
};

复杂度分析

  • 时间复杂度:O (n),其中 n 是数组的长度。我们只需要遍历一次数组。
  • 空间复杂度:O (1),只使用了常数级的额外空间。

方法二:覆盖补零法

思路

  1. 先遍历数组,把所有非零元素依次覆盖到数组的前面,用一个变量 stack_size 记录当前覆盖的位置。
  2. 遍历完成后,stack_size 及之后的位置全部补零即可。

代码实现

cpp

复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int stack_size = 0;
        // 第一步:把非零元素移到前面
        for (int x : nums) {
            if (x != 0) {
                nums[stack_size++] = x;
            }
        }
        // 第二步:后面的位置全部补零
        while (stack_size < nums.size()) {
            nums[stack_size++] = 0;
        }
    }
};

复杂度分析

  • 时间复杂度:O (n),两次遍历数组,总时间还是线性的。
  • 空间复杂度:O (1),同样是原地操作。

方法对比

方法 优点 缺点
双指针交换法 只需一次遍历,操作次数更少 交换操作会多写几次赋值
覆盖补零法 逻辑直观,容易理解 需要两次遍历,操作次数略多

在进阶要求 "尽量减少操作次数" 时,双指针交换法会更有优势。


总结

这道题的核心是原地修改保持相对顺序,两种方法都能满足要求。

相关推荐
不正经学生1 小时前
C语言预处理详解:编译器真正动手之前的那些事
c语言·开发语言·算法·面试·bug
毕竟是shy哥4 小时前
计算YOLO数据集中每个类的目标数
算法·yolo·机器学习
M78佐菲4 小时前
Linux学习笔记:TCP协议
linux·笔记·学习·tcp/ip·算法
圣保罗的大教堂4 小时前
leetcode 1406. 石子游戏 III 困难
leetcode
richdata5 小时前
商品数字化不是先做大数据,而是先把数据变成可用决策
大数据·运维·数据治理·商品数字化·智能补货·ai商品决策
晊晌_h5 小时前
嵌入式从0到精通——数据结构总结[特殊字符]
数据结构·算法·排序算法
我找到地球的支点啦6 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信
罗西的思考6 小时前
【OpenClaw具身硬件】ZeroClaw 源码阅读笔记(3)--- RAG
人工智能·算法·机器学习
极新6 小时前
中国机器人已出海至141国,售后服务正成为新的机会
大数据·人工智能·机器人
AI_yangxi7 小时前
靠谱的短视频矩阵系统
大数据·人工智能·矩阵