leetcode283---将所有零0移动到末尾,其余元素次序不变

一、题目介绍

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


说明: 必须在原数组上操作,不能拷贝额外的数组。 尽量减少操作次数。
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

来源:力扣(leetcode)
链接: moveZero.
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、解题思路

1.暴力解法

对于没有头绪的算法题,我们一般可以先尝试暴力解法,然后层层递进优化,下面是我参考力扣题解里老汤老师的讲解,总结这道题

① 我们想要求的结果是一个数组,那么一开始就可以构造一个长度等于nums的数组,初始化为0。
在这里插入图片描述
② 现在要做的就是把nums数组里非0的元素依次放入tmp数组中。
做法:遍历Nums数组,如果非0(i指针),将其放入tmp中第一个0元素(j指针)。依次增加
在这里插入图片描述
然后,题目要求,输入的数组还是nums数组,即还需要将tmp数组一个个拷贝进入nums数组;

代码如下(暴力解法):

//时间复杂度O(n)
//空间复杂度O(n)
public void moveZeros1(int[] nums){
        if(nums == null || nums.length == 0){
            return;
        }
        int[] tmp = new int[nums.length];
        //记录tmp数组第一个为0的元素
        int j = 0;
        for (int i = 0; i < nums.length ; i++) {
            if(nums[i] != 0){
                tmp[j] = nums[i];
                j++;
            }
        }
        for (int i = 0; i < nums.length; i++) {
        	nums[i] = tmp[i];
    	}
}

2.双指针优化空间

优化:在常量级别的条件下,即O(1)
在nums一个数组上 引入两个指针,i(代表当前元素),j(代表i指的当前非0元素将要移入的位置)
在这里插入图片描述

原地算法:在原始输入数组上完成的算法,没有申请额外的空间

代码如下(双指针算法):

	//时间复杂度为o(n)  遍历一遍数组
    //空间复杂度 O(1)
    public void moveZeros(int[] nums){
        if(nums == null || nums.length == 0){
            return ;
        }
        //下一个非零元素存储的位置
        int j = 0;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] != 0){
                //交换i和j指向的元素
                int tmp = nums[i];
                nums[i] = nums[j];
                nums[j] = tmp;
                j++;
            }
        }
    }

3.引出快慢指针的概念

本题目中,根据以上分析,i走的比较快,j指针走的比较慢,为提高代码阅读效率。

将指针 i 名字改成 fast,指针 j 改成slow。这里仅仅引入快慢指针的概念。

4.继续优化,减少操作数量

观察第三步的代码,思考还有无进一步优化的空间。
判断数组为空不可以省略,接下来还必须判断元素是否为0,所以for循环不可以再有所改进,再观察for循环体内,当前是元素不为0时,交换元素。

此时考虑能否减少元素交换的次数,来提升算法性能。

思考:什么时候可以减少元素交换?

① 当fast == slow时,元素没有必要去交换
在这里插入图片描述
所以,改进代码如下:

//多加一个判断,来减少元素交换次数
if(slow != fast){
	//进行交换
}

② 不进行两个元素交换,而是去更新赋值操作

交换元素,需要对元素访问两次,但是赋值操作只需要访问一次内存就可以

如下:
在这里插入图片描述
想想我们的初始目的是:将非0元素全部移动到前面,要实现这样的操作,除了去交换元素,也可以去直接去给nums[slow]赋值。
在这里插入图片描述
(直接将nums[slow] == nums[fast])
当fast跳出循环之后,剩下的操作是,将slow所指后面的元素其他值赋值为0。

代码改写如下:

public void moveZeroes(int[] nums) {
    if (nums == null || nums.length == 0) {
        return;
    }
    int slow = 0;
    for (int fast = 0; fast < nums.length; fast++) {
        if (nums[fast] != 0) {
            // 减少赋值的次数
            if (slow != fast) { 
            //不在交换两个元素,而是对nums[slow]赋值
                nums[slow] = nums[fast];
            }
            slow++;
        }
    }
    for (; slow < nums.length; slow++) {
        nums[slow] = 0;
    }
}

三、结果

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值