在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如:如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
首先想到的方法是将数组进行排序,我们遍历一遍数组就可以找出重复的数字了。排序一个数组的时间复杂度为O(nlogn)。
我们还可以使用哈希表来解决这一问题。我们从头到尾遍历数组,如果哈希表中不存在当前遍历的数字,那么就在哈希表中存放这个数字;如果当前遍历的数字存在哈希表中了说明这个数字就是重复的。这个方法的时间复杂度为O(n),但是空间复杂度为O(n)。我们思考有没有空间复杂度为O(1)的方法。
根据题目我们知道数组大小为n,所有数字的范围为0至n-1,显然,如果不存在重复的数字当数组排序后下标i对应的数字就是i;如果存在重复的数字有些位置存在多个数字,而有的位置没有数字。
算法思路如下:
从头遍历数组中的每个数字,每次扫描到的数字记为m。当扫描到下标为i的数字是,首先比较m是否等于i:
- 如果相等,直接扫描下一个数字;
- 如果不相等,再拿m和第m个数字相比较:
- 如果它和第m个数字相等那么我们就找到了一个重复数字。
- 如果它和第m个数字不相等,就把第i个数字和第m个数字交换,把m放到属于它的位置上。再重复这个比较、交换过程,直至找到重复的数字。
实现代码:
public static boolean DuplicatedNum(int numbers[],int length,int[] duplication) {
if(numbers==null||length==0||duplication==null){
return false;
}
for(int i=0;i<length;i++){
if(numbers[i]<0||numbers[i]>length-1){
return false;
}
}
for(int i=0;i<numbers.length;i++){
int m=numbers[i];
if(i==m){
continue;
}else{
if(m==numbers[m]){
duplication[0]=m;
return true;
}else{
int temp = numbers[i];
numbers[i] = numbers[m];
numbers[m] = temp;
}
}
}
return false;
}