283. 移动零

题目

自己写通过的:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slow = 0, fast = 0;
        while (fast < nums.size())
        {
            if (nums[slow] == 0 && nums[fast] != 0) 
            {
                nums[slow] = nums[fast];
                nums[fast] = 0;
            }
            if (nums[slow] != 0) slow ++;
            fast ++;
        }
    }
};

基本思想就是在更换时一定是要nums[slow] == 0nums[fast] != 0同时满足,然后slow查找值为0的位置,当找到值为0的位置时,就不动了,直到更换了两个数,导致这个slow位置的数不为0,然后执行slow ++,至于fast则是从头到尾遍历整个数组,找出值不为0的位置,然后在nums[slow] == 0 && nums[fast] != 0满足时,更换位置,注意每次while循环都要执行fast ++

然后就是在做这题的时候自己也踩了些坑,感觉还是有必要写下的:

第一个坑就是读题目的时候有点粗心,没看清楚全部要满足的条件,导致第一次写的时候写了如下代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;
        while (left < right)
        {
            if (nums[left] == 0)
            {
                nums[left] = nums[right];
                nums[right] = 0;
                right --;
            }
            else left ++;
        }
    }
};

这段代码虽然也能把所有 0 移动到数组的末尾,但是没有保持非零元素的相对顺序。

第二个坑就是有点想当然,直接把slow ++放第一个if里面了,也就是如下代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slow = 0, fast = 0;
        while (fast < nums.size())
        {
            if (nums[slow] == 0 && nums[fast] != 0) 
            {
                nums[slow] = nums[fast];
                nums[fast] = 0;
                slow ++;
            }
            fast ++;
        }
    }
};

错误的原因就是认为当更换两个位置的数时,要让slow ++,但是没考虑到当slow对应的元素不为0时,也要让slow ++,因为要让slow位置的元素为0,等待right位置的不为0的元素来进行交换。

再附上分析的两张图:

img

第二张图其实就是我踩的第二个坑的第一个不通过的案例

img

最后看了下官方题解,也有些收获

img

官方代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int n = nums.size(), left = 0, right = 0;
        while (right < n) {
            if (nums[right]) {
                swap(nums[left], nums[right]);
                left++;
            }
            right++;
        }
    }
};

感觉官方思路是从一个更大的更宏观的角度去考虑的,刚开始并没有考虑left,而是从right出发,用right来遍历整个数组,看right位置的数值是不是不为0,如果不为0,则一定是放在前面的,也就是slow位置,然后再slow ++,来满足左指针左边均为非零数,同时为下个可能要更换的数做准备;

对官方思路举个例子来理解:

img

首先l和r是预设为同步状态的,当r指向的元素为0时,l和r就不同步了,因为l要停下来记录这个位置(即r指向的元素为0时的位置),然后r继续往前走找到第一个不为0的数,来和l指向的数交换,此时那个元素0就到r那个位置去了,之后再++l。

又看了卡哥的讲解

卡哥认为本题和移除元素其实是一个套路。

相当于对整个数组移除元素0,然后slowIndex之后都是移除元素0的冗余元素,把这些元素都赋值为0就可以了。

给出卡哥代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (nums[fastIndex] != 0) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        // 将slowIndex之后的冗余元素赋值为0
        for (int i = slowIndex; i < nums.size(); i++) {
            nums[i] = 0;
        }
    }
};
posted @ 2024-11-07 18:24  hisun9  阅读(19)  评论(0)    收藏  举报