题目:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3.
分析:因为这个数组的长度是n并存放了n个数字,如果这个数组的数字没有重复,那么排序之后,它的数字和数组下标应该是一一对应的。那么由于数组中存在重复的数字,就会有些数字的下标没有对应的数字,而是对应其他数字。
具体怎么做?首先我们可以重排这个数组,假设该数组为a。从头开始,当扫描到下标为i的数字时,此时这个位置存放的值我们设为m。如果i=m,则跳到下标为i+1的数字;如果i≠m,则比较m与a[m]的值。如果m=a[m],那么我们就找到了重复的值了,如果不相等,则将m放到a[m]处,而a[m]放到a[i]处。接下来就是重复这个过程了。
我们以上面的a[7]={2,3,1,0,2,5,3}为例分析。
a[7]={2,3,1,0,2,5,3},a[0]=2,0≠2->a[2]=[1],2≠1=》a[7]={1,3,2,0,2,5,3};
a[7]={1,3,2,0,2,5,3},a[0]=1,0≠1->a[1]=[3],1≠3=》a[7]={3,1,2,0,2,5,3};
a[7]={3,1,2,0,2,5,3},a[0]=3,0≠3->a[3]=[0],3≠0=》a[7]={0,1,2,3,2,5,3};
接下来会一直到a[4];
a[7]={0,1,2,3,2,5,3},a[4]=2,4≠2->a[2]=2,这个时候就找到了重复的值了,搞定!
代码示例如下:
#include<stdio.h>
int duplicate(int numbers[],int length){
int i,temp,duplicate;
if(numbers == NULL || length <= 0)
return -1;
for(i = 0; i < length; ++i){
if(numbers[i] < 0 || numbers[i] > length - 1)
return -1;
}
for(i = 0; i < length; ++i){
while(numbers[i] != i){
if(numbers[i] == numbers[numbers[i]]){
duplicate = numbers[i];
return duplicate;
}
temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
return -1;
}
int main(){
int a[7] = {2,3,1,0,2,5,3};
int length,i;
length = sizeof(a)/sizeof(int);
for(i = 0; i < length; i++)
printf("%d ",a[i]);
printf("\n");
printf("%d\n", duplicate(a,7));
for(i = 0; i < length; i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
public class t1 {
public static int duplicate(int[] num,int len) {
if(num == null || len <= 0) {
return -1;
}
for(int i = 0; i < len; ++i) {
if(num[i] < 0 || num[i] > len - 1)
return -1;
}
for(int i = 0; i < len; ++i) {
while(num[i] != i) {
if(num[i] == num[num[i]]) {
int n = num[i];
return n;
}
int temp = num[i];
num[i] = num[temp];
num[temp] = temp;
}
}
return -1;
}
public static void main(String[] args) {
int[] number = {1,2,3,4,6,7,5,3};
int length = number.length;
System.out.println(duplicate(number,length));
return;
}
}