这次代码完全正确,可以通过 LeetCode 283. 移动零。
你的解法是双指针思想(读写指针)+ 两次遍历,时间复杂度为 \(O(n)\),空间复杂度为 \(O(1)\)。
一、完整代码(精简注释)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int n = nums.size();
int left = 0; // 记录下一个非零元素的存放位置
// 第一次遍历:将所有非零元素依次移动到数组前面
for (auto x : nums) {
if (x != 0) {
nums[left] = x;
left++;
}
}
// 第二次遍历:将剩余位置全部填充为 0
for (int i = left; i < n; i++) {
nums[i] = 0;
}
}
};
二、解题思路
第一步:移动非零元素
for (auto x : nums) {
if (x != 0) {
nums[left] = x;
left++;
}
}
这里:
-
x:依次读取数组中的元素。 -
left:记录下一个非零元素应该存放的位置。 -
遇到非零元素,就放到
nums[left],然后left++。 -
遇到零元素,直接跳过。
例如:
nums = {0, 1, 0, 3, 12};
第一次遍历结束:
nums = {1, 3, 12, 3, 12};
left = 3;
此时,数组前面三个位置已经存放了所有非零元素。
第二步:填充零元素
for (int i = left; i < n; i++) {
nums[i] = 0;
}
从 left = 3 开始,将剩余位置全部修改为零。
最终:
nums = {1, 3, 12, 0, 0};
三、最终总结(CSDN 笔记版)
- 解题思路
使用读写双指针思想,将所有非零元素移动到数组前面,再将剩余位置填充为零。
-
核心步骤
-
定义
left = 0,表示下一个非零元素的存放位置。 -
遍历数组,遇到非零元素,将其写入
nums[left]。 -
每写入一个非零元素,
left++。 -
第一次遍历结束后,
left等于非零元素的数量。 -
从
left开始,将数组剩余位置全部填充为零。 -
复杂度分析
-
时间复杂度:\(O(n)\),两次遍历数组。
-
空间复杂度:\(O(1)\),直接在原数组上操作。
- 注意事项
-
left只在遇到非零元素时增加。 -
for(auto x : nums)中的x是元素的副本,不是下标。 -
因为写入位置始终不会超过当前读取位置,所以覆盖操作不会破坏后续尚未读取的元素。
-
第二次遍历必须从
left开始,而不是从0开始。
一句话总结:使用 left 记录非零元素的写入位置,先将非零元素依次前移,再将剩余位置全部补零。
这道题和上一道最长连续序列的区别在于:上一题利用哈希集合快速查找元素,这一题利用读写指针实现数组的原地修改。