Problem: 283. 移动零
首先我们来讲一下本题的思路
int*
这种指针,而是直接使用数组下标来充当指针即可好,那我们就来看看这个双指针到底是怎样的,要如何去使用
cur
是我们用来遍历数组的,从[cur, n - 1]
就是还未处理的元素;那么从[0, cur]
就是已经处理过的元素,但是呢本题的要求是我们要划分出【零元素】与【非零元素】,所以呢前面的区间我们可以再度划分为[0, dest]
和[dest + 1, cur - 1]
小结一下:
[0, dest] [dest + 1, cur - 1] [cur, n - 1]
[0, dest]
—— 非零元素[dest + 1, cur - 1]
—— 零元素[cur, n - 1]
—— 未处理元素接下去我们就通过画算法图解的形式来模拟一下解题的过程
[0, cur - 1]
这段区间是没有任何数据的,所以在一开始我们可以将【dest】这个指针置于-1的位置cur++
即可,将其留在这个位置上[0, dest]
这个区间就是用来存放非0元素的,此时多了一个元素的话那dest
就要加1,原本其是指向-1这个位置,那我们可以使用++dest
来完成cur++
cur
再后移之后呢,我们又碰到了非0元素,继续让dest
上来然后交换二者位置上的元素++dest
,然后做交换[cur, n - 1]
的这段区间也不存在了,说明已经没有待处理元素了接下去我们来分析一下本题的时空复杂度
本算法的核心思路参考的是【快速排序】的区间划分,我们这里就是在不断遍历数组的过程中,以中间的0作为分割,然后左侧是非0元素,右侧是未处理的元素。在处理的过程中我们只是遍历了一次这个数组,所以复杂度为 O ( n ) O(n) O(n)
在本题中我们并没有去开出额外的空间,所以复杂度为 O ( 1 ) O(1) O(1)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
for(int dest = -1, cur = 0; cur < nums.size(); ++cur)
{
if(nums[cur] != 0)
{
swap(nums[++dest], nums[cur]);
}
}
}
};