🔥个人主页:Milestone-里程碑
❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>
<<Git>><<MySQL>>
🌟心向往之行必能至
题目描述
给定一个数组nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。注意:必须在不复制数组的情况下原地对数组进行操作。
示例
- 输入:
nums = [0,1,0,3,12] - 输出:
[1,3,12,0,0]
方法一:双指针交换法
思路
我们可以用一个指针left来记录当前非零元素应该放置的位置,然后遍历数组。当遇到非零元素时,就将它与left位置的元素交换,并让left指针右移。这样可以保证left指针之前的所有元素都是非零的,且保持了原有顺序。
代码实现
cpp
class Solution { public: void moveZeroes(vector<int>& nums) { int left = 0; for (auto& x : nums) { if (x != 0) { swap(x, nums[left]); left++; } } } };复杂度分析
- 时间复杂度:O (n),其中 n 是数组的长度。我们只需要遍历一次数组。
- 空间复杂度:O (1),只使用了常数级的额外空间。
方法二:覆盖补零法
思路
- 先遍历数组,把所有非零元素依次覆盖到数组的前面,用一个变量
stack_size记录当前覆盖的位置。 - 遍历完成后,
stack_size及之后的位置全部补零即可。
代码实现
cpp
class Solution { public: void moveZeroes(vector<int>& nums) { int stack_size = 0; // 第一步:把非零元素移到前面 for (int x : nums) { if (x != 0) { nums[stack_size++] = x; } } // 第二步:后面的位置全部补零 while (stack_size < nums.size()) { nums[stack_size++] = 0; } } };复杂度分析
- 时间复杂度:O (n),两次遍历数组,总时间还是线性的。
- 空间复杂度:O (1),同样是原地操作。
方法对比
| 方法 | 优点 | 缺点 |
|---|---|---|
| 双指针交换法 | 只需一次遍历,操作次数更少 | 交换操作会多写几次赋值 |
| 覆盖补零法 | 逻辑直观,容易理解 | 需要两次遍历,操作次数略多 |
在进阶要求 “尽量减少操作次数” 时,双指针交换法会更有优势。
总结
这道题的核心是原地修改和保持相对顺序,两种方法都能满足要求。