题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
返回描述:
如果数组中有重复的数字,函数返回true,否则返回false。
如果数组中有重复的数字,把重复的数字放到参数duplication[0]中。(ps:duplication已经初始化,可以直接赋值使用。)
思路分析
最暴力的解法:对数组进行排序,排序后的数组,比较两个相邻的数是否相等 ,排序一个长度为n的数组为O(nlogn).该方法对原数组进行了修改
利用哈希表的不可重复性:对数组遍历一边,如果表中存在这个元素,则记录dup中,返回true,否则添加 时间复杂度O(n),空间复杂度,是一个大小为O(n)大小的哈希表 ,对原数组没有修改,且能知道第一次出现重复的值
import java.util.*;
public class Solution {
public boolean duplicate(int numbers[],int length,int [] duplication) {
if(numbers==null||length<0){
return false;
}
HashSet<Integer> set= new HashSet();
for(int i=0;i<length;i++){
if(set.contains(numbers[i])){
duplication[0]=numbers[i];
return true;
}
set.add(numbers[i]);
}
return false;
}
}
上述都没有用到题目中所给的所有数字都在0到n-1的范围内这个条件,思考一下如果数组没有重复值,那么长度为n的数组中的值肯定能和0~n-1这些数值中的值一一对应起来,所以,我们可以让原始数组的每一个下标都对应下标的值,如果在交换的过程中发现,发现与下标对应的值相等则说明找到
public boolean duplicate(int numbers[],int length,int [] duplication) {
if(numbers==null||length<=0){
return false;
}
for(int i=0;i<length;i++){
while(numbers[i]!=i){
if(numbers[i]==numbers[numbers[i]]){
duplication[0]=numbers[i];
return true;
}
swap(numbers,i,numbers[i]);
}
}
return false;
}
public void swap(int[] nums,int i,int j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
注意,此方法只能找到任意一个重复的值,但找不到第一个重复的值,(例如,6,3,2,0,2,5,0)该程序输出重复的值0但正确应该是 2,所以要看清楚题目
拓展:在一个长度为n+1的数组里的所有数字都在1到n的范围内。所以数组至少有一个数字是重复的。请找出数组中任意一个重复的数字。但不能修改数组。
可以使用O(n)的额外空间,像上述那样解决问题 。下面是避免使用O(n)的辅助空间
/**
* 在一个长度为n+1的数组里的所有数字都在1到n的范围内。所以数组至少有一个数字是重复的。请找出数组中任意一个重复的数字。但不能修改数组
*/
//思路:在数字范围1...n上二分,对每次的左半部分 若果,数组中的数字在这个范围上个数小于二分长度,那右半部分一定有重复的数字,如果大于二分长度
//一定在左半部分,依次递归,直到不能再分时结束递归
int dup[] = new int[1];
public int getDuplication(int[] nums, int length,int start, int end) {
if (nums == null || nums.length == 0) {
return -1;
}
if (start == end) {
dup[0] = start;
return start;
}
int mid = start + ((end - start) >> 1);
int i = CountRange(nums, length, start, mid);//每次递归都计算出左范围,数组中有的个数
if (i > (mid - start + 1)) {//左边这个范围上一定有重复的 继续递归
getDuplication(nums, length, start, mid);
} else {//
getDuplication(nums, length, mid+1, end);
}
return dup[0];
}
/*
数组在这个start ...end长度范围上有多少个值
*/
public int CountRange(int[] nums, int length, int start, int end) {
int count=0;
if (nums == null) {
return -1;
}
for (int i = 0; i < length; i++) {
if (nums[i] >= start && nums[i] <= end) {
count++;
}
}
return count;
}