Day3:LeeCode Hot3-移动零

大家好,今天开启 LeetCode Hot100 系列 的第三篇:移动零。

这道题是双指针的标杆入门题,也是算法刷题、前端/后端面试的基础必考题型。

题目看似简单,实则考察数组原地操作、双指针思想、空间复杂度优化等核心能力,掌握本题思路可以完美迁移至「数组元素移除、元素筛选」等同类题型,性价比极高。

一、题目描述

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

必须在原数组上操作,不能拷贝额外的数组,尽量减少操作次数。

示例:

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

题目核心要求:

  • 所有非零元素前置,保持原有相对顺序不变

  • 所有零元素后置

  • 原地修改数组,O(1) 额外空间

二、解题核心思路

很多初学者第一反应是遍历数组删除0、末尾补0,但普通删除会导致数组元素频繁前移,效率极低,且容易出现索引错位问题。

本题最优解题思想是快慢双指针,核心逻辑一句话概括:慢指针记录非零元素的待放置位置,快指针遍历寻找所有非零元素。

通过双指针可以一次遍历完成元素筛选,避免重复操作,完美满足原地修改、低时间复杂度的要求。

三、快慢指针解法

1. 思路分析

  • 快指针 fast:全程遍历数组,逐个扫描所有元素,负责寻找非零元素。

  • 慢指针 slow:指向数组左侧待填充的位置,专门用来存放筛选出来的非零元素。

遍历过程:快指针找到非零元素后,将元素赋值给慢指针位置,随后慢指针右移占位;遍历结束后,慢指针左侧全部是有序非零元素,最后将慢指针及之后的位置全部补0即可。

2. 完整代码实现(Java)

public void moveZeroes(int[] nums) {
    // 慢指针:记录非零元素填充位置
    int slow = 0;
    // 快指针:遍历整个数组
    for (int fast = 0; fast < nums.length; fast++) {
        // 找到非零元素,进行填充
        if (nums[fast] != 0) {
            nums[slow] = nums[fast];
            slow++;
        }
    }
    // 慢指针之后的位置全部补0
    for (int i = slow; i < nums.length; i++) {
        nums[i] = 0;
    }
}

3. 分步流程(以 nums = [0,1,0,3,12] 为例)

  1. fast=0,元素为0,跳过,slow不变;

  2. fast=1,元素为1,nums[slow]=1,slow=1;

  3. fast=2,元素为0,跳过,slow不变;

  4. fast=3,元素为3,nums[slow]=3,slow=2;

  5. fast=4,元素为12,nums[slow]=12,slow=3;

  6. 遍历结束,slow=3,将下标3、4全部补0,最终数组 [1,3,12,0,0]。

4. 复杂度分析

  • 时间复杂度:O(n),n 为数组长度,仅两次线性遍历,无嵌套循环,效率最优。

  • 空间复杂度:O(1),仅使用两个指针变量,完全原地修改数组,无额外数组开销。

四、高频易错点总结

1. 破坏非零元素相对顺序

部分同学会采用首尾双指针相向遍历,快速交换零元素,但该写法会打乱非零元素顺序,不满足题目要求,面试严禁使用。

2. 忽略原地操作要求

新建数组存储非零元素、最后补0的写法虽然结果正确,但占用O(n)额外空间,不符合题目进阶要求,面试会扣分。

3. 索引越界问题

补零循环从slow开始,而非0,若从0开始会覆盖已排序的非零元素,是新手高频bug。

4. 全零/无零边界 case

两种双指针解法均可天然兼容 [0,0,0]、[1,2,3] 等边界数组,无需额外判空处理。

五、刷题总结

1. 题型定位

本题是数组双指针(快慢指针)的核心模板题,核心思想:一个指针遍历,一个指针占位筛选有效元素。
作为数组双指针的入门模板题,移动零这道题的刷题价值远不止解题本身,核心是掌握原地筛选数组元素的通用解题思维,这里对核心刷题要点做系统性总结,方便后续举一反三、固化解题模板。

2. 面试答题策略

面试优先写出基础双指针赋值解法,逻辑通俗易懂、零bug风险。

posted @ 2026-08-27 11:43  帅也是一种罪孽  阅读(14)  评论(0)    收藏  举报