[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]

这一题咋看之下非常简单,但是是medium难度,因此肯定没有我想的那么简单(实际真的是那么简单),下面说明两种方法:

方法一:

显然是用HashSet来做,把所有的数字存进去,然后如果遇到相同的,就加入list,就是这么简单。(竟然还通过了)

代码如下,很显然,这种方法速度太慢了,假如重复的数字很少,那后面的查找时间会很大,理论复杂度O(n)+kO(1),实际复杂度大致是在当前数量级上大于n,n前系数较大,只打败了6%的提交:

public class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> lResult = new LinkedList<>();
        Set<Integer> set = new HashSet<>();
        for (int i : nums) {
            if (set.contains(i)) {
                lResult.add(i);
            } else {
                set.add(i);
            }
        }
        return lResult;
    }
}

方法二:

事实上,题中给出了一个很重要的条件,那就是1 ≤ a[i] ≤ n (n = size of array),换句话说,数组中的元素不可能大于数组的size,不会出现这种情况:[1,10000,2],因此,我们可以这样来做,直接创建一个一样大的数组,在数组上作标记就可以了。

代码如下,复杂度为O(n),实际时间为n,打败了96%的提交(这一题实在是太简单):

    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> lResult = new LinkedList<>();
        int[] nMarks = new int[nums.length+1];
        for (int i = 0; i < nums.length; i++) {
            nMarks[nums[i]] ++;
            if (nMarks[nums[i]]>1) {
                lResult.add(nums[i]);
            }
        }
        return lResult;
    }

实际上,上面的代码有个小问题,就是如果一个数字超过2次,会被加入list中多次,这个是不可以被允许了(实际上,LeetCode这一题的本意本来就是一个数字最多出现两次),因此稍稍修改了以后,如下面的代码:

    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> lResult = new LinkedList<>();
        int[] nMarks = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
            nMarks[nums[i]]++;
        }
        for (int i = 0; i < nMarks.length; i++) {
            if (nMarks[i] > 1) {
                lResult.add(i);
            }
        }
        return lResult;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值