LeetCode 442——Find All Duplicates in an Array

Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.

Find all the elements that appear twice in this array.

Could you do it without extra space and in O(n) runtime?

 

Example:

Input:
[4,3,2,7,8,2,3,1]

Output:
[2,3]

 


 

这道题目如果去掉 "without extra space" 这个要求,将退化成一个非常经典的通过hashmap来解决的问题(或者通过int数组的下标当作key的方式来构建一个类似的hashmap,可以有更快的速度)。

那么不通过额外空间来解决这道题该怎么做呢?有两种做法不同,但是思想相同的解题思路:

第一种,因为 “1 ≤ a[i] ≤ n (n = size of array)” 这个条件,所以有a[i] - 1对应的范围就是数组下标的范围,我们可以令absNum = Math.abs(a[i]),当 a[a[i] - 1] > 0 时,将a[a[i] - 1]变为负数,还是因为上个条件的限制,a[i]是不可能存在负数的,所以这就可以标志这个下标已经被访问过了。进而下一次访问重复的下标的时候,a[a[i] - 1]一定是负数。

第二种,因为 “1 ≤ a[i] ≤ n (n = size of array)” 这个条件,所以有a[i] - 1对应的范围就是数组下标的范围,我们可以对 a[i] 和 a[a[i] - 1] 进行相等判断,若不相等,则交换位置。也就是期望下标 i 对应的值 a[i] = i + 1。所以,等交换完毕后,再次遍历此数组,若下标 i 不满足a[i] = i + 1,则证明为重复元素。

很明显,两种方法利用的条件是一样的,利用 a[i] - 1 的范围在数组下标范围内的隐含特性,遍历数组并构造出可以检测重复元素的条件。

同时利用这个条件还需要另一个条件的支持,那么就是每个数字最多只会重复两次,如果可以重复任意次的话,那么判断出的重复数字结果也会重复,还需要去重步骤,更加大了难度。所幸题目有这个限制条件。

 

而我一开始的想法是利用已知长度后,数组内不带重复元素时的加和是固定的特点来做文章,可惜这样做是无法准确找到重复元素的,所以方向也就是错误的。

 

但是今天真的是被震惊了好多次,同一道题,别人的代码,简洁、明了、思路流畅;而我的代码,复杂、难看、不达要求。在看评论的时候,发现了一个和我感受一样的外国朋友:

希望能通过努力来弥补这些差距吧。

 


 

AC代码:

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
       List<Integer> result = new ArrayList<>();
        int numLen = nums.length;

        for (int i = 0; i < numLen; ++i) {
            int absNum = nums[i] > 0 ? nums[i] : -nums[i];

            if (nums[absNum - 1] > 0) {
                nums[absNum - 1] = -nums[absNum - 1];
            } else {
                result.add(absNum);
            }
        }

        return result;
    }
}

 


如有错误,欢迎指摘。也欢迎通过左上角的“向TA提问”按钮问我问题,我将竭力解答你的疑惑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值