283. 移动零(C++)

题目

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

  • 必须在原数组上操作,不能拷贝额外的数组。
  • 尽量减少操作次数。

题解与分析

反向遍历—对0元素冒泡

我们需要对数组进行遍历,遭遇到的0元素全部移动到数组的末尾,考虑到正序冒泡的话,遍历的同时,for循环的边界由于容器尾部堆积的0元素,将导致循环边界不断动态的变化,因此我们考虑反向进行遍历,代码如下:

class Solution {
public:
    void zeroToEnd(vector<int>& nums, int move,int size) {
        for (int i = move; i < size-1; i++) {
            int tmp = nums[i+1];
            nums[i+1] = nums[i];
            nums[i] = tmp;
        }
    }
    void moveZeroes(vector<int>& nums) {
        int size = nums.size();
        for (int i=size-1; i >= 0; i--) {
            if (nums[i] == 0) {
                zeroToEnd(nums, i, size);
            }
        }
    }
};

本质是两个for循环的嵌套,时间复杂度为O(n^2)。

正向遍历—交换非0元素

除了遍历数组的for循环的下标i之外,我们再定义一个下标j指向容器头部,每当发现非0元素就进行填充并j向前移位:

  • i==j时,遍历到当前位置不存在非0元素

  • j<i时,遍历到当前位置前已经存在非0元素

    一旦出现非0元素,ij俩下标永远不会相等。

0元素会以跟非0元素交换的方式,逐位向尾部移动。代码如下:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int size = nums.size();
        //用于指代当前非0元素的位置
        int j = 0;
        for (int i = 0; i < size; ++i) {
            if (nums[i] != 0) {
                //当前非0元素位置随着遍历进行更新非0元素
                nums[j] = nums[i];
                //当下标不对等,说明有填充0的空位
                if (i != j) {
                    //把0与当前下标的元素进行调换
                    nums[i] = 0;
                }
                //如果目前没有非0元素,则目前为止的顺序不需要进行调动
                //正常移动下标即可
                j++;
            }
        }
    }
};
posted @ 2020-12-01 09:28  脱线森林`  阅读(96)  评论(0编辑  收藏  举报