[LC] 442. Find All Duplicates in an Array

看到最初始的条件,1 <= a[i] <= n (n = size of array)。我最开始能够想到的是https://blog.csdn.net/chaochen1407/article/details/43230993

上面这种做法的根本就是让众神归位,就是把数字放到放到它该呆的位置,也就是把num放到arr[num - 1],然后上面那题,是找到不存在的数字,而这一题,则是找到重复的数字。这种做法确实能够成功,只是要注意的是,上面那题,找的是缺失,所以我们放的过程里不需要注意什么,而这一题,找的是重复,所以存在重复运算的可能,所以当我们找到重复的时候,我们需要把其中的一个重复重置为0,否则会出现多余的运算甚至死循环。譬如说[1,2,6,5,4,6],如果你只交换不重置,那么在arr[3]的那个位置就会和arr[6]无限交换或者类似的问题会出现。所以整套流程就是,和first missing positive一样,在一个位置上不停的换,有两个交换的终止条件:1. 在当前i这个位置上,换出了arr[i] = i + 1,也就是归位了。2. arr[i] == arr[arr[i] - 1],这种情况是重复出现,需要把当前数字录入到结果当中,然后把arr[i]或者arr[arr[i] - 1]置0即可。 遍历完整个数组就可以得到全部的答案了。根据这样,可以得到如下代码:

    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new LinkedList<>();
        for (int i = 0; i < nums.length; i++) {
            while (nums[i] != i + 1 && nums[i] != 0) {
                int target = nums[i] - 1;
                if (nums[target] == nums[i]) {
                    res.add(nums[i]);
                    nums[target] = 0;
                    break;
                } else {
                    int tmp = nums[i];
                    nums[i] = nums[target];
                    nums[target] = tmp;
                }
            }
        }
        
        return res;
    }   

第二个做法就相对简单很多了,其实原理也是一样的。用数组的index作为标记,也就是用arr[i - 1]作为对于i的标记,只是我们不再置换,用的是另一种方式做标记。因为我们可以知道数组里面的数字全部大于0,所以其实正负数也是作为一个标记的方式,譬如说,在{1,6,2,3,4,2}里,我们访问到第一个2的时候,就把arr[2 - 1]也就是arr[1]置负,那么当我们走到第二个2的时候,我们就知道arr[1]已经被访问过了,所以这个2就是一个重复的数字,可以直接放到结果数组里,其实这样performance更高,而且代码也会变的更加的简单。

    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new LinkedList<>();
        for (int i = 0; i < nums.length; i++) {
            int num = Math.abs(nums[i]);
            if (nums[num - 1] < 0) {
                res.add(num);
            } else {
                nums[num - 1] *= -1;
            }
        }
        
        return res;
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值