题目
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1
的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入: [2, 3, 1, 0, 2, 5, 3] 输出:2 或 3
限制:2 <= n <= 100000
算法思路
本题思路大致分为三种。
方法一:使用哈希表来记录,依次遍历,如果哈希表中没有该数字,就加入哈希集中,存在就说明该数字重复了,返回即可。该方法时间和空间复杂度都是O(N)。
方法二:排序,再依次遍历,存在相邻两个数字相等,返回该数字即可。该方法时间复杂度为O(NlogN),即排序的复杂度,空间复杂度为O(1)。
方法三:原地置换,首先这道题目中表明了数组中的数字的范围在**(0 ~ n-1)**,而数组的长度为n,通过索引来记录则不会存在数组越界。
如果没有重复数字,那么正常排序后,数字i应该在下标为i的位置,所以思路是重头扫描数组,遇到下标为i的数字如果不是i的话,(假设为m),那么我们就拿与下标m的数字交换。在交换过程中,如果有重复的数字发生,那么终止返回改数字。
该方法时间复杂度O(N),空间复杂度为O(1)。
代码
class Solution {
/*************** 哈希表 时间O(N) 空间 O(N)**********************/
public int findRepeatNumber1(int[] nums) {
if(nums == null || nums.length == 0) return -1;
Map<Integer,Integer> map= new HashMap<>();
for(int i : nums){
if(map.containsKey(i)) return i;
map.put(i,1);
}
return -1;
}
/*************** 排序 时间O(NlogN) 空间 O(1)**********************/
public int findRepeatNumber2(int[] nums) {
if(nums == null || nums.length == 0) return -1;
Arrays.sort(nums);
for(int i = 0;i<nums.length-1;i++)
if(nums[i] == nums[i+1]) return nums[i];
return -1;
}
/*************** 鸠占鹊巢 时间O(N) 空间 O(1)**********************/
public int findRepeatNumber(int[] nums) {
if(nums == null || nums.length == 0) return -1;
for(int i = 0;i < nums.length;i++){
while(nums[i] != i){
if(nums[nums[i]] == nums[i]) return nums[i]; //nums[i]作为索引
//以i为索引的值和以nums[i]为索引处的值互换
int tmp = nums[i];
nums[i] = nums[tmp];
nums[tmp] = tmp;
}
}
return -1;
}
}
很明显,本题最理想的方法是方法三,原地置换。