这是一道谷歌的面试题,一个大小为n的数组,里面的数都属于范围[0, n-1],有不确定的重复元素,找到至少一个重复元素,要求O(1)空间和O(n)时间
这题目的难点就是他的限制条件,只能是o(1)的空间和o(n)的时间,所以我们不能使用hashmap来统计重复的值,但是可以使用Hashmap的思想,
根据题目,我们可以把给定的数组当做一个hashmap,利用基数排序的方式找到重复的数。
分析思路如下:
下面以2,4,1,5,7,6,1,9,0,2这十个数为例,展示下如何用基数排序来查找重复元素。
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 2 | 4 | 1 | 5 | 7 | 6 | 1 | 9 | 0 | 2 |
(1)由于第0个元素a[0] 等于2不为0,故交换a[0]与a[a[0]]即交换a[0]与a[2]得:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 1 | 4 | 2 | 5 | 7 | 6 | 1 | 9 | 0 | 2 |
(2)由于第0个元素a[0] 等于1不为0,故交换a[0]与a[a[0]]即交换a[0]与a[1]得:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 4 | 1 | 2 | 5 | 7 | 6 | 1 | 9 | 0 | 2 |
(3)由于第0个元素a[0] 等于4不为0,故交换a[0]与a[a[0]]即交换a[0]与a[4]得:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 7 | 1 | 2 | 5 | 4 | 6 | 1 | 9 | 0 | 2 |
(4)由于第0个元素a[0] 等于7不为0,故交换a[0]与a[a[0]]即交换a[0]与a[7]得:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 9 | 1 | 2 | 5 | 4 | 6 | 1 | 7 | 0 | 2 |
(5)由于第0个元素a[0] 等于9不为0,故交换a[0]与a[a[0]]即交换a[0]与a[9]得:
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 2 | 1 | 2 | 5 | 4 | 6 | 1 | 7 | 0 | 9 |
(6)由于第0个元素a[0] 等于2不为0,故交换a[0]与a[a[0]]即交换a[0]与a[2],但a[2]也为2与a[0]相等,因此我们就找到了一个重复的元素——2。
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
数据 | 2 | 1 | 2 | 5 | 4 | 6 | 1 | 7 | 0 | 9 |
package google;
public class RepeatNumber {
/**
* 一个大小为n的数组,里面的数都属于范围[0, n-1],有不确定的重复元素,找到至少一个重复元素,要求O(1)空间和O(n)时间。
*/
public static void swap(int i,int j ,int num[]){
int temp;
temp=num[i];
num[i]=num[j];
num[j]=temp;
}
public static int findRepeatNumber(int num[],int n){
int repeatNum=-1;
for(int i=0;i<n;i++){
while(i!=num[i]){
if(num[i]==num[num[i]])
return num[i];
swap(num[i],num[num[i]],num);
}
}
return repeatNum;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int num[]={0,1,2,2,4,5,6,6};
int repNum=findRepeatNumber(num,8);
if(repNum==-1)
System.out.println("没有重复的数");
else
System.out.println("重复的数为"+repNum);
}
}
该本章是在总结MoreWindows的基础之上写的,感谢MoreWindows提供的思路,原文出处http://blog.youkuaiyun.com/morewindows/article/details/8204460