LeetCode 283. 移动零
本节目标
稳定压缩全部非零元素,再原地填零。
这题是双指针解题框架中稳定压缩的典型例子:先确定前缀应该放什么,再统一处理剩余位置。
题意与约束
把所有零移动到数组末尾,同时保持非零元素的相对顺序。函数没有返回值,必须直接修改 nums。
推导与不变量
不断把一个零与后面的元素交换,会让相同元素移动多次。先扫描所有元素:任意时刻,nums[0..write) 按原顺序保存已读到的非零值。扫描结束后,这个前缀已正确,只需把 [write, n) 填为零。
原地修改
函数的结果体现在原数组 nums,返回值为 None/void。非零元素的相对顺序保持不变,尾部由填零阶段完成,额外空间为 O(1)。
代码实现
两份源码先写入非零元素,再从 write 位置开始补零;第二阶段不需要知道原来每个零的位置。
- C++
- Python
C++17
#include <vector>
using namespace std;
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int write = 0;
for (int read = 0; read < static_cast<int>(nums.size()); read++) {
if (nums[read] != 0) {
nums[write] = nums[read];
write++;
}
}
while (write < static_cast<int>(nums.size())) {
nums[write] = 0;
write++;
}
}
};
Python 3
class Solution:
def moveZeroes(self, nums: list[int]) -> None:
write = 0
for value in nums:
if value != 0:
nums[write] = value
write += 1
while write < len(nums):
nums[write] = 0
write += 1
复杂度分析
- 时间复杂度:
O(n),两段扫描总长度不超过2n。 - 空间复杂度:
O(1)。
易错点
- 在扫描非零元素时把零提前写回,可能覆盖还未读取的值。
- 只做压缩不补零,数组尾部会保留旧值。
模式迁移
“先稳定保留,再批量补齐”也适用于按谓词过滤数组、分离正负元素等问题。若只要求把零放到末尾而不要求相对顺序,可以改用两端交换。