[leetcode刷题之旅]283.移动零

1、题目解析

题目链接

在这里插入图片描述
将所有0都移动到数组的末尾,并保证数组中非零数的排序是不变的。

这题很简单,但是不能新开数组,不然可以使用新开数组直接移动数据会在逻辑上更好理解和实现。

2、实现代码

2.1 暴力求解

    public void moveZeroes(int[] nums) {
        for(int i = 0;i<nums.length; i++){
            if(nums[i] == 0) {
                for(int j=i+1; j<nums.length; j++) {
                    if(nums[j] != 0) {
                        nums[i] = nums[j];
                        nums[j] = 0;
                        break;
                    }
                }
            }
        }
    }

这里暴力求解的思路很简单,在最外层的循环中对数组中的每个元素进行遍历,遇到非零数就跳过,遇到0就进入下一层循环,找到下一个非零数交换数据。

2.2 计0法

public void moveZeroes(int[] nums) {

    int PointA = 0, PointB = 0;

    for (; PointA<nums.length; PointA++) {
        if(nums[PointA] != 0) {
            nums[PointB++] = nums[PointA];
        }else {
            for(; PointA<nums.length&&nums[PointA]==0 ; PointA++) {}
            nums[PointB++] = nums[PointA];
        }
    }

    for (;PointB<nums.length; PointB++) {
        nums[PointB] = 0;
    }
}

暴力法通过双重循环直接移动数组元素,使程序会消耗大量时间在寻找0和非0数的过程。在遇到一些特殊情况,比如非零数全部集中在数组尾部的情况时两重循环都需要把数组全遍历一遍。因此演化出一种只需要一重循环的新算法。在第一次循环中将所有非零数移动到数组头部,同时遇到0就让计非0指针(PointB)自增。当第一次循环结束时,PointB记录的就是原数组中非零的个数。

接下来的第二重循环中,由于我们在第一次循环中把非零数全部前移,PointB记录的就是最后一个非零数的索引,那么在(PointB,nums.length)区间中的所有数都应该是0。那么直接把后面的元素全部置0即可。

2.3 计0法的引申

这个方法是我在访问leetcode国际站看到的一个小姐姐Olsh的解法,大家有兴趣可以去看看。

网页链接
在这里插入图片描述

从提交结果可以看出这种方法其实在内存消耗和执行用时都相当出色。

    public void moveZeroes(int[] nums) {

        int zeroes = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0){
                zeroes++;
            }else {
                if(zeroes != 0){
                    nums[i - zeroes] = nums[i];
                    nums[i] = 0;
                }
            }
        }
    }

其实这种方法应该算是计0法和暴力法的结合。同样只需要一重遍历,完成了记录0的个数并交换数据两个工作。

这里的含义其实是,遇到0不处理,让计0标记加1,然后在遇到非0数时往前移动,移动的距离就是前面计0的个数,并且把原来位置的数据置0。这种方法执行到后期可以在尾部产生一串0,因为非零数都移动到数组前部。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值