283. Move Zeroes

一、题目
Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the non-zero elements.

For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0].

Note:
You must do this in-place without making a copy of the array.
Minimize the total number of operations.
二、分析和解答
题意要求:把0值放在数组的后面,保持非0值的顺序保持不变。但要in-place进行排序,不能进行复制。
1、我的想法:
(1)找到非零值 的个数
(2)把非零值提前
(3)后面补零
代码如下:

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

    }

AC
2、我回想的一个算法,如何不消耗空间来交换两个数的值?使用异或操作。即针对同一变量异或两次,值不变。
3、别人代码:对第一二步进行优化。压缩非0值,也是把它迁移,但是这个for循环很巧妙。

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

        for(int j=count;j<nums.length;j++){
            nums[j] = 0;
        }

    }

补充:这个也是快慢指针的意思。一个指针不停地向后扫描,找到非零位置,然后和前面的那个指针count交换位置即可,我这种也对。
4/别人代码:保持两个指针,一个指向0值,一个指向非零值,当正好一对的时候(0,非0),进行交换。我未成功,下一遍再补充吧

   public void moveZeroes(int[] nums) {
        int zero = 0;
        int non = 0;
        while(zero<nums.length && non<nums.length){
            while(zero<nums.length && nums[zero] != 0)
                zero++;
            while(non<nums.length && (nums[non] == 0 || non < zero))
                non++;
            if(zero<nums.length && non<nums.length){        
                nums[zero] = nums[zero]^nums[non];
                nums[non] = nums[zero]^nums[non];  
                nums[zero] = nums[zero]^nums[non];
            }

        }
    }

(1)while(zero<nums.length && nums[zero] != 0)前后两个条件不能交换,必须是这个顺序,因为后面后zero++,当zero达到nums.length的时候,在数组里面肯定就越界了,这样可以防止越界!快排里面也是这个道理。
(2)while(non<nums.length && (nums[non] == 0 || non < zero))这两个也得保证顺序。但是一般人肯定都会忽略non < zero这个条件,所以案例中会出现[1,0]。zero开始会指向0值,non会指向1值,然后交换输出成了[0,1],显然这是错误的,因此在这种情况下,让non继续向前走就是了。这是什么情况呢?其实就是本身就是正确顺序的情况,non的指针会在zero的前面,1在0前面本身就正确。
(3)两个数的交换要使用异或的方法在原地进行交换,不会使用额外的空间,前面的那种交换使用了额外的空间,是错误的。
(4)其实追根到底,这题和快排都属于那种使用两个快慢指针来进行操作的情况,这是一种类型的题,以后要注意了。
补充:注意了,这里while的条件和快排里面的可是不一样的,这里是小于长度,快排是low < high。这里是因为这两个指针都是从前向后遍历,因此比较的是数组最后的那一位;而快排是两个指针从两边向中间移动,最后会到达中间的位置,因此比较的是low和high。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值