图解算法——数组移动零

1、题目描述

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/move-zeroes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2、示例

示例1:

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

说明:

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

3、解题思路

看到这道题,由于题目限制了不能有额外空间消耗,所以暴力法求解思路是:从前往后遍历(或从后往前遍历),遇到一个0,就进行类似 “冒泡” 排序的操作,将0 移动到数组最后。

代码如下:

class Solution {
    public void moveZeroes(int[] nums) {
        int l = 0;
        int r = nums.length-1;
        for(int i = r; i>=l; i--){
            if(nums[i] == 0){
                for(int j = i; j<r; j++){
                    nums[j] = nums[j+1];
                }
                nums[r] = 0;
                r--;
            }
        }
    }
}

问题似乎解决了,我们提交一下看看结果如何:

 

 

 果然,耗时是比较严重的,拖了后腿。

因为在这里你的算法复杂度是O(N^2);

那么有没有复杂度为O(n)的办法呢?

 

当我们看到这里,不知道有没有思路想到“双指针”?

是的,一般情况下,双指针就是解决数组元素交换问题的。但是有人说了,上面的思路不就是双指针嘛?

是的,上面的思路也是双指针,不过不同的是,上面的思路是一左一右指针。左指针是固定的,不会变,只有右指针在变化。

而下面这个思路是,左右指针都在变化。我们设定一左一右指针left 和 right,且初始值都是0。

我们以right 为驱动,当right 下标所在位置不为0 时,我们交换left 和 right两个位置的数据,然后left++ 且 right ++;当right 下标处不为0 时,right ++。这里left 代表数组左侧第一次以0 开头元素下标(如:数组 [5,6,8,7,0,0,3],left就是下标为4的0元素),right 表示右侧遍历的下标。

故,代码如下:

class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length, left = 0, right = 0;
        while (right < n) {
            if (nums[right] != 0) {
                swap(nums, left, right);
                left++;
            }
            right++;
        }
    }

    public void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }
}

提交看看:

 

 果然,由于时间复杂度的降低,耗时果然减少了许多。

 

小结:

注意在数组中双指针的使用。

 

 

Over......

posted @ 2021-08-24 23:33  额是无名小卒儿  阅读(108)  评论(0编辑  收藏  举报