简单LeetCode 283动画补充中引导学习
移动零
快慢指针:写指针归位
慢指针指向"下一个非零元素该放的位置":遍历时每遇到非零数就和慢指针位置交换、慢指针右移——一趟结束后非零数整齐在前、0 自然沉底。
时间复杂度 O(n)空间复杂度 O(1)
题单:面试热题
题目描述
给定一个数组,把其中的 0 全部移动到数组末尾,同时保持所有非零元素的相对顺序。要求原地操作,不能拷贝整个数组。
学习目标
能说清读指针/写指针的分工,并解释交换为什么能同时完成"非零前移"和"零沉底"。
已完成 0 / 6 阶段
诊断
先看两个约束
题目要求"原地"和"保持非零相对顺序",这两条分别排除了哪些做法?
建议先完成当前阶段(提示 / 检查 / 自评),再进入下一步;也可以直接跳过。
解题思路
核心思想
慢指针指向"下一个非零元素该放的位置":遍历时每遇到非零数就和慢指针位置交换、慢指针右移——一趟结束后非零数整齐在前、0 自然沉底。
为什么需要它
原地 + 保持顺序,意味着不能排序也不能整块搬运;需要一个"边扫描边归位"的机制。
第一反应:直觉方案
新建一个数组:先放所有非零数,再补足 0——逻辑最直白,但不满足"原地"要求(需要 O(n) 额外空间)。
关键洞察
关键洞察是"保序搬运本质上是压缩":把非零元素压缩到数组前部,等价于用一个只前进的写指针记录"已压缩区域的长度"。读指针扫到什么决定写不写,两个指针分工明确——这就是快慢指针的通用形态。
时间复杂度 O(n)空间复杂度 O(1)
易错点
- 用交换(而不是覆盖)更省心:非零数归位的同时,0 被换到后面去了
- 保持非零元素相对顺序——不能像快排分区那样两头夹逼
- 注意读指针一直线性前进,不要去"跳过"数组中的 0 后回头处理
参考代码
参考代码
1function moveZeroes(nums) {
2 let write = 0; // 下一个非零元素要放的位置
3 for (let read = 0; read < nums.length; read++) {
4 if (nums[read] !== 0) {
5 [nums[write], nums[read]] = [nums[read], nums[write]];
6 write += 1;
7 }
8 }
9}
逐步演示
这道题目前是索引版:题面、解题思路与双语言代码已是完整内容; 逐步动画会按计划补充。