面试题03. 数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
解法一:利用Hash表判断
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public int findRepeatNumber(int[] nums) {
//通过Hash表判断
int length = nums.length;
int[] hashArray = new int[length];
for(int i = 0;i < length;i++){
if(hashArray[nums[i]] != 0){
return nums[i];
}else{
hashArray[nums[i]]++;
}
}
return -1;
}
}
解法二:改变数组结构(原地Hash)
时间复杂度:O(n)
空间复杂度:O(1)
class Solution {
public int findRepeatNumber(int[] nums) {
//通过改变数组结构实现
int length = nums.length;
for(int i = 0;i < length;i++){
while(nums[i] != 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;
}
}
解法三:利用二分查找法
因为题目设定长度为n的数组中,所包含的为0~n-1的数字。
原本值为mid的数字前一定就有mid个数字(从0开始),每次判断数组中<=mid的数字个数,判断重复数字出现的范围。
方法可能会在某用例下错误。
比如用例中mid = i 时,恰好重复的数字存在于mid前,恰好 <= mid的个数 = (mid - start + 1) ,就会判断错误。
用例:{2,2,3,4,5}
先计算mid = (1 + 5) / 2 = 3
遍历数组发现 <= 3 的有三个数字,就会判断错误。
class Solution {
public int findRepeatNumber(int[] nums) {
//二分查找
int length = nums.length;
int start = 0;
int end = length - 1;
while(start <= end){
int mid = (end - start)/2 + start;
int count = countFun(nums,start,mid);
if(start == end){
if(count > 1){
return start;
}else{
break;
}
}
if(count > (mid - start + 1)){
end = mid;
}else{
start = mid + 1;
}
}
return -1;
}
public int countFun(int[] nums,int start,int end){
int count = 0;
int length = nums.length;
for(int i = 0;i < length;i++){
if(nums[i]>= start && nums[i] <= end){
count++;
}
}
return count;
}
}