leetcode 283.移动零

leetcode283.移动零

  • 一、题目
  • 二、题解
    • 1. 暴力法(超时)
    • 2. 双指针法(快慢指针)
      • 2.1 两次循环
      • 2.2 一次循环

一、题目

难度:简单


给定一个数组 nums,编写一个函数将所有 0移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例:

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

提示:

  • 1 1 1 <= nums.length <= 1 0 4 10^4 104
  • − 2 31 -2^{31} 231 <= nums[i] <= 2 31 − 1 2^{31} - 1 2311

二、题解

1. 暴力法(超时)

时间复杂度: O ( n 2 ) O(n^2) O(n2)

一看题目很简单,直接暴力法两个for循环直接解决问题。结果不出意料地寄了(超时),这样对数组的操作次数太多了。

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

2. 双指针法(快慢指针)

时间复杂度: O ( n ) O(n) O(n)

2.1 两次循环

还是两个for循环,不过不是嵌套的循环。采用双指针法,第二次循环利用慢指针在非零元素之后补零。

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int size = nums.size(), j = 0;
        // 快慢指针筛去 0
        for(int i = 0; i < size; i++) {
            if(nums[i] != 0) {
                nums[j++] = nums[i];
            }
        }
        // 利用慢指针补零
        for(int k = j; k < size; k++) {
            nums[k] = 0;
        }
    }
};

2.2 一次循环

这样写是可以通过了,但是第二次循环有点多余。我们可以直接在第一次循环中把覆盖操作改为交换操作,直接将所有的0顶(有点冒泡的感觉)到数组后面。代码如下:

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

你可能感兴趣的:(leetcode,算法,算法,leetcode,c++)