剑指Offer_#3_数组中重复的数字

剑指Offer_#3_数组中重复的数字

Contents

题目

找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

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

限制:

2 <= n <= 100000

思路分析

方法1:使用HashSet或HashMap

HashSet和HashMap都是java当中collection框架里的一部分,他们的区别如下:

HashMap和HashSet的区别
HashMap和HashSet的区别

我们可以把数组元素加入HashSet或者HashMap(作为键),利用了这两种数据结构数据的唯一性,当遇到重复的数组元素的时候,就直接返回这个元素即可。

方法2:原地交换数组元素

因为题目当中限制了数组元素的大小是在0~n-1范围内,如果每个数字只出现一次,刚好可以按顺序排列在长度为n的数组当中。
那么可以将每个数组元素的数字(nums[i])放到下标nums[i]处,这样处理之后,所有位置满足nums[i] == i

算法流程
循环遍历整个数组,

  • 如果nums[i] == i,满足要求,所以不做处理
  • 如果nums[i] != i,进行判断
    • 如果nums[i] == nums[nums[i]],说明出现重复了,返回nums[i]
    • 如果nums[i] != nums[nums[i]],说明还没有放到应该在的位置,将nums[i]nums[nums[i]]交换位置。

比起方法1,这个方法空间没有借助额外的变量,空间复杂度是O(1)

方法3:排序后比较相邻元素

先将数组排序,那么重复数字必然相邻。然后遍历排序后的数组,每次比较当前数字和后一个数字,如果相同,返回当前数字。

解答

解答1:使用HashSet

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<Integer>();
        for(int i = 0; i <= nums.length - 1;i++){
            if(!set.contains(nums[i])) set.add(nums[i]);
            else return nums[i];
        }
        return -1;//表示遍历了nums,也没有找到重复的
    }
}

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n)

关于HashSet

疑问:
这里边直接就使用Set,这个Set属于什么类型呢?是一个接口?还是抽象类?还是具体类?
解答:
Set是接口,不可以实例化,但是Set类型的变量可以指向实现了Set接口的实体类的对象。
例如:
Set<int> set = new HashSet<int>(); (X)泛型的尖括号中间只可以传入包装类或者自定义的类,不可以传入类似于int这样的基本类型。
正确写法:
Set<Integer> set = new HashSet<Integer>();

疑问:
能否这么写?set.addAll(nums)
解答:
不可以,nums是普通数组,而非合集框架里边的类,所以不可以作为addAll这个方法的参数。

解答2:原地交换数组元素

class Solution {
    public int findRepeatNumber(int[] nums) {
        for(int i = 0;i <= nums.length-1;i++){
            if(nums[i] != i){//这里也可以写while,但是我觉得用while很奇怪,反正写if或者while都能过
                if(nums[i] == nums[nums[i]]) return nums[i];
                else{
                    int tmp = nums[i];
                    nums[i] = nums[tmp];
                    nums[tmp] = tmp;
                }
            }
        }
        return -1;//没找到
    }
}

复杂度分析

时间复杂度:O(n)
空间复杂度:O(1)

解答3:排序后比较相邻元素

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

复杂度分析

时间复杂度:O(nlogn),因为排序的复杂度是O(nlogn)
空间复杂度:O(1)

原文地址:https://www.cnblogs.com/Howfars/p/13405276.html