问题
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
来源:力扣(LeetCode)
链接:链接
题解
1.双重循环暴力解题(最简单,最费时)
思路:
当双重循环中nums[i] == nums[j]时 该值就为重复的数字
代码:
public int findRepeatNumber(int[] nums){
for( int i = 0; i < nums.length; i++){
for( int j = 0; j < nums.length; j++){
if(nums[i] = nums[j])
return nums[i];
}
}
return -1;
}
复杂度分析
时间复杂度:O(n^2)
0<nums.length<10000, 当数组长度达到10w,代码的性能就很差了
空间复杂度:O(1)
2.HashMap解题
思路:
看见题目的第一反应就是用HashMap将nums中的值存到map的k,使用map.containsKey(Object k),
当返回true时,该K就是重复的数字(因为最近使用map.containsKey()比较多,所以选择这个Map解题,但是后来想想直接用Set更简单一些)
public int findRepeatNumber(int[] nums){
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int num : nums){
if(map.containsKey(num))
return num;
map.put(num,0);
}
return -1;
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n) 哈希查找的空间复杂度为O(1)
3.HashSet解题
思路:
同 HashMap
代码:
public int findRepeatNum(int[] nums){
Set<Integer> set = new HashSet<Integer>();
for(int num : nums){
//set.add(T value) 若set中无该元素则存入set并返回true
if(!set.add(num))
return num;
}
return -1;
}
时间复杂度:O(n)
空间复杂度:O(n)
4.使用数组代替HashSet
思路
初始化一个临时数组,将元素组的值当做临时数组的下标,该值+1,若临时数组的值大于1,则该值就为重复的值。
虽然时间复杂度和空间复杂度和HashSet解题的相同,但是使用数组性能有很大提升,主要因为两个方面:
1. 哈希表底层是使用数组+红黑树组成的,而数组也是用不满的,有加载因子。所以使用数组代替哈希表可以节省空间。
2. 哈希表在判重的时候要经过哈希计算,可能存在哈希冲突,而数组可以直接通过index找到内存位置,所以性能更好
代码
poublic int findRepeatNum(int[] nums){
int[] temp = new int[nums.length];
for( int i = 0; i<nums.length; i++){
temp[nums[i]++;
if(temp[nums[i]]>1)
return nums[i];
}
return -1;
}
时间复杂度:O(n)
空间复杂度:O(n)
5.在原数组上解题
思路
移动原数组,以下标 与 值 相等与否为判定条件,若不相等,则判定值与该值作为下标的值是否相等,若相等则为重复的数,若不相等互换。这样空间复杂度就为O(1)
代码
public int findRepeatNum(int[] nums){
for(int i = 0; i<nums.length;i++){
while(i!=nums[i]){
if(nums[i] == nums[nums[i]]{
return nums[i];
}
int temp = nums[nums[i]];
nums[nums[i]] = nums[i];
nums[i] = temp;
}
}
return -1;
}
复杂度
时间复杂度:O(n)
空间复杂度:O(1)