442. Find All Duplicates in an Array

3 篇文章 0 订阅
3 篇文章 0 订阅

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]

题意很好理解,就是在整型数组中找出重复的数,还没有算法思维的我,首先想到的就是暴力循环

 public List<Integer> findDuplicates(int[] nums) {
        List<Integer> resoult = new ArrayList<>();
        for (int i=0;i<nums.length;i++){
            for (int j=i+1;j<nums.length;j++){
                if (nums[i] == nums[j]){
                    resoult.add(nums[i]);
                    break;
                }
            }
        }
        return resoult;
    }

很显然, LeetCode直接报了Time Limit Exceeded。时间上不允许,我们必须在遍历第一遍的同时就把重复的数给找出来。

    如何才能做到一次遍历就能找出重复的数呢?用我们人类的思维去考虑,当我们在读这个数组的时候,读到重复的数很自然就知道前面有没有出现,我们也是就读了一遍;这是因为我们读过这个数之后都会在大脑里面做个标记,等到再次读到这个数是就很很清楚这个数已经出现过了。
    同理,那么我们让计算机也拥有同种思维,题中有一个很关键的条件1 ≤ a[i] ≤ n,根据这个条件我们应该有思路了,我们用类似哈希表作用的数组来实现,计算机每遍历一个数,就用这个数当下标在哈希数组里面做个标记,等到再次读到这个数的时候只需要进行判断就可以了。

上代码

public List<Integer> findDuplicates(int[] nums) {
        int[] hashMap = new int[nums.length+1];
        List<Integer> resoult = new ArrayList<>();
        for (int num : nums ){
            if (hashMap[num] == 1 ){
                resoult.add(num);
            }else {
                hashMap[num] = 1;
            }
        }
        return resoult ;
    }

这种思路还可以衍生出以下解体方法,我们直接在数组本身上面做标记,因为1 ≤ a[i] ≤ n,所以数组里面的值都是正数,所以计算机每遍历一个数,我们就把这个数当作下标,然后在对应下标位置的数乘以-1,标记一下,这样再遍历到重复的数的时候,只需要判断正负,计算机就知道这个数是否已经出现过

 public List<Integer> findDuplicates(int[] nums) {
        List<Integer> resoult = new ArrayList<>();
        for (int num : nums){
            int index = Math.abs(num)-1;
            if (nums[index] < 0){
                resoult.add(index+1);
            }else {
                nums[index] *= -1;
            }
        }
        return resoult;
    }

在碰到 1 ≤ a[i] ≤ n 这种条件时,应该要往这中思路上考虑一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值