刷题系列之283. 移动零

84 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

前言

题目来源

leetcode.cn/problems/mo…

题目介绍

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

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

题目分析

根据题目意思,已知一个数组,将数组的元素如果是0,将它往后移动一位。那么反过来理解,如果这个元素不是0,那么就将它往前移动一位交换位置,如果第一个元素就不是0,那么就是0和0交换,不变。如果第二个是0,第三个不是0,那么第三个和第二个交换位置,这样那么为0的元素就往后移动了一位。

题目解答

class Solution {
    public void moveZeroes(int[] nums) {
        int n=nums.length;
        //定义一个位置递增的变量
        int num=0;
        for(int i=0;i<n;i++){
        //如果不为0,那么交换位置
            if(nums[i]!=0){
                int temp=nums[i];
                nums[i]=nums[num];
                nums[num]=temp;
                //每次碰到不为0的元素 ,累加1。这样如果是第一个是0,第二个是0,第三个不是0,第四个不是0,那么i=2的时候,将nums[2]和nums[0]交换,i=3的时候,将nums[3]和nums[1]交换
                num++;
            }
        }
    }
}

如上代码验证

image.png

image.png

这么一看 这个方式的效率还是比较低一些。

官方答案验证

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;
    }
}

image.png

原理差不多,记录位置交换顺序,包装一个方法,也节省了内存。

看记录,有题友也提供了更简便的方法

 public void moveZeroes(int[] nums) {
         int index = 0;
        for (int num : nums) {
            if (num != 0) {
                nums[index++] = num;
            }
        }
        for (int i = index; i < nums.length; i++) {
            nums[i] = 0;
        }
    }

这个方式运行如下

image.png

这样跑起来的更高效,内存也更少。利用的原理是,先把不为0的元素赋值依次从下标0开始的位置,这样就有一个变量记录到了多少个元素不为0,依次按顺序排放了。

接下来把剩余位置的元素,依次赋值0。这样就完全符合题目要求了。相对这个方式更容易理,也更稳妥。

总结

解题方式看来都是有比较多种的,多看看别人的分析,自己也能领会更多的解题思路。