主题
复盘 · LC 283 移动零
题目
- 题号:LeetCode 283
- 名称:移动零(Move Zeroes)
- 难度:Easy
- 链接:leetcode.cn/problems/move-zeroes
- 今日代码:
283-移动零/index.js
题意
给定数组 nums,把所有 0 原地移到末尾,其余非零元素保持相对顺序不变。
- 必须修改原数组;LeetCode 函数签名一般是
void,不依赖返回值。 - 尽量少操作次数(进阶)。
边界:全零、无零、只有一个元素、零与非零交错。
涉及算法
| 标签 | 一句话 |
|---|---|
| 同向双指针 / 读写指针 | 慢指针写下一个非零该放的位置,快指针扫描 |
| 原地改写 | 先把非零「挤」到前面,再把尾部填 0 |
教程对照:06 · 同向双指针与快慢指针。
评价我的解法
思路:遇到 0 就 splice 删掉,再 push(0),并用 count 限制扫描上界。
我的代码(摘自 283-移动零/index.js,不含本地测例):
javascript
var moveZeroes = function (nums) {
let index = 0;
let count = 0;
while (true) {
if (index >= nums.length - count) {
break;
}
if (nums[index] === 0) {
nums.splice(index, 1);
nums.push(0);
count++;
} else {
index++;
}
}
return nums;
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 结果:相对顺序能保住,样例
[0,1,0,3,12]→[1,3,12,0,0]正确。 - 问题:
splice中间删除是 O(n),零很多时整体易到 O(n²)。- 题目强调原地;返回
nums不影响判题,但面试应说「改原数组即可」。 while (true)+ 手动break能用,但读写指针一次for更清晰。
小结:能过 Easy,复杂度意识和「原地数组模板」还欠一截——这题正是练读写指针的好题。
最佳题解
快慢指针(一次遍历):
javascript
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function (nums) {
let slow = 0;
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) {
// 交换:把非零换到 slow,零自然被换到后面
const tmp = nums[slow];
nums[slow] = nums[fast];
nums[fast] = tmp;
slow++;
}
}
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
等价写法:先把非零依次写到前面,再从 slow 起填 0。
- 时间 O(n),空间 O(1)。
- 为何更优:每个下标常数次读写,没有中间段元素整体搬移。
- 可视化:快慢指针逐步演示(浏览器打开,点「下一步」)。
关联题目
| 题 | 为何相关 |
|---|---|
| 27. 移除元素 | 同一套读写指针,删掉指定值 |
| 26. 删除有序数组中的重复项 | 慢指针写「下一个该保留的位置」 |
| 75. 颜色分类 | 原地分区,双/三指针进阶 |
一句话带走
移动零 = 读写指针:快指针找非零,慢指针写位置;别靠反复 splice。
