
可以用「双指针」一次遍历,时间复杂度 O(n)、空间复杂度 O(1),满足原地修改和保持相对顺序的要求。
思路:
-
用一个指针
slow指向当前应该放"下一个非零元素"的位置。 -
用另一个指针
fast从头到尾遍历数组:- 每当
nums[fast] != 0,就把该非零元素放到nums[slow],然后slow++。
- 每当
-
第一遍结束后,
slow之前的元素都是按原顺序排好的非零元素。 -
接下来从
slow到数组末尾全部填 0 即可。
这样能保证:
-
所有非零元素的相对顺序不变(因为我们按原顺序从左到右拷贝过去)。
-
0 都被集中到末尾。
-
原地操作,只使用了常数额外空间。
代码实现(C++)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int n = nums.size();
int slow = 0; // 指向下一个应该放非零元素的位置
// 1. 把所有非零元素按原顺序移动到前面
for (int fast = 0; fast < n; ++fast) {
if (nums[fast] != 0) {
nums[slow] = nums[fast];
++slow;
}
}
// 2. slow 之后填充为 0
while (slow < n) {
nums[slow] = 0;
++slow;
}
}
};
复杂度分析
-
时间复杂度:O(n),只遍历了一次数组,再加一次填 0。
-
空间复杂度:O(1),未使用额外数组,原地修改。