题目链接:283. 移动零 - 力扣(LeetCode)
算法原理
解法一:辅助数组
开辟一个辅助数组,遍历原数组,每次遍历到非0元素的时候,就把它放入辅助数组里,最后让辅助数组覆盖原数组,但这是异地操作,不符合题目原地移动的要求、
解法二:利用双指针(注意是使用变量充当指针,不是真的第一个指针出来,i = 0,相当于有一个指针指向0下标)
移动零这类题非常经典,叫做数组分块,这道题是数组分两块,将数组在某些特定条件下分成两块,左边部分是非0,右边是0,它是快速排序最核心的一步,解法有特别多种,利用双指针是最经典的解法
定义两个指针:
- cur:标记非0元素的最后一个位置(上图右边)
- i:扫描数组
整个数组会结合这个 i 分成三个区域,[0, cur] 非0区域,[cur+1, i-1] 0区域,0[i, n-1]待扫描区域,用题目中的示例,[0,1,0,3,12],cur指向-1下标,i指向0下标,一开始 i 指向0元素,直接i++,0还是在 [cur+1, i-1] 区域的,i 指向非0元素,因为有0的干扰,[cur+1] 位置有个0,可以把0交换到 i 这个位置,再让cur++,就把这个非0元素包含在 [0, cur] 区域了,下图是模拟过程,可以参考理解
分类讨论:
- 遇到 0:直接 i++
- 遇到 1:swap(cur + 1,i),cur++,i++
代码:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
for(int i = 0, cur = -1; i < nums.size(); ++i)
{
if (nums[i]) //非0元素
//交换完cur+1后cur还要向后走,直接先自增
swap(nums[++cur], nums[i]);
}
}
};