剑指 Offer 03. 数组中重复的数字

851 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

题目:给定一个长度为n的数组nums,在nums中所有数字都在0~n-1范围内。但数组中存在某些数字是重复的,重复的数字未知,且可能存在多个数字重复,重复的数量不定。请找出数组中重复的任何一个数字。

例如:

输入:
	[2, 3, 1, 0, 2, 5, 3]
输出:23 

解题思路

本题是一道简单题,也就意味着我们可以重拳出击了,哈哈哈~

HashSet 解决

看完题目,首先想到的就是HashSet,因为题目只要求找到一个重复的即可,并不需要找出所有满足条件的值,而SetMap都具有判定当前元素是否在集合中的特性,因此可以直接使用Set来存储元素的值,之后碰到存在的直接返回即可,代码如下:

public int findRepeatNumber(int[] nums) {
    HashSet<Integer> set = new HashSet<>();
    for(Integer num:nums){
        if(set.contains(num)){
            return num;
        }else {
            set.add(num);
        }
    }
    return -1;
}

时间复杂度为O(N)O(N),空间复杂度也是O(N)O(N)

如果要求不能使用Java自带的Set,我们可以使用数组来存储对应元素的数量,如果数量大于一定值,也直接返回,可得代码:

public int findRepeatNumber(int[] nums) {
    int[] count = new int[nums.length];
    for(Integer num:nums){
        count[num]++;
        if(count[num]>1) return num;
    }
    return -1;
}

时间复杂度为O(N)O(N),空间复杂度也是O(N)O(N)。上述代码实际耗时4ms,速度较慢,将代码改成下面的:

public int findRepeatNumber(int[] nums) {
    int len = nums.length;
    int[] count = new int[len];
    for(int i=0;i<len;i++){
        count[nums[i]]++;
        if(count[nums[i]]>1) return nums[i];
    }
    return -1;
}

复杂度没有变化,但实际耗时2ms。之所以变快是因为之前的代码使用的是foreach的遍历方式,每次存入count数组还要进行Integerint的转化,因此建议使用下面的循环进行遍历。

排序

如果数组中存在重复元素,那排序后必然是挨着的,因此我们可以先对数组进行排序,之后判断相邻的元素是否相等即可,代码如下:

public int findRepeatNumber(int[] nums) {
        Arrays.sort(nums);
        int len = nums.length;
        for(int i=1;i<len;i++){
            if(nums[i]==nums[i-1]) return nums[i];
        }
        return -1;
    }

但时间复杂度变成了O(nlogn)O(nlogn),空间复杂度为O(1)O(1)

原地哈希

哈希的思想是将数组中对应的元素对哈希表的长度进行取余,之后将元素填入余数的位置。原地哈希就是将数组元素保持不变,将原数组看作是一个哈希表,将数组元素存入对应下标的位置,因此本题原地哈希会有两种可能:

  1. 数组元素nums[i]所对应的元素不等于i,并且nums[i]nums[nums[i]]不相等,则此时需要将nums[i]nums[nums[i]]进行交换。
  2. 数组元素nums[i]所对应的元素不等于i,并且nums[i]nums[nums[i]]相等,则此时直接返回即可。

代码如下:

public int findRepeatNumber(int[] nums) {
    int len = nums.length;
    for(int i=0;i<len;i++){
        while(nums[i]!=i){
            if(nums[i] == nums[nums[i]]) return nums[i];
            swap(nums, nums[i], i);
        }
    }
    return -1;
}

时间复杂度为O(N)O(N),空间复杂度为O(1)O(1)