题目一:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3.
思路一:利用hash表,新建一个相同长度的数组,遍历原数组,每遍历一个元素,判断新数组中对应的下标(例如元素为2,对应下标就为2)是否含有该元素,如果没有,新数组对应的下标存储该元素,如果已经含有该元素,说明该元素重复,输出。
解法一:(时间复杂度为O(n),空间复杂度为O(n))
public class Test1 {
public static void main(String[] args) {
// int[] a={2,3,1,0,4,5,6};
// int[] a={2,3,1,0,4,5,3};
// int[] a={2,3,1,0,2,5,3};
// int[] a={2,3,10,0,2,5,3};
int[] a =null;
int index=findChongfu(a);
if(index==-2){
System.out.println("数组不正常");
}else if(index==-1){
System.out.println("数组中没有重复元素");
}else{
System.out.println("数组中一个重复元素为:"+index);
}
}
private static int findChongfu(int[] a) {
if(a==null||a.length<=0){
return -2;
}
int length=a.length;
for(int i=0;i<length;i++){//判断非法元素
if(a[i]<0||a[i]>length-1){
return -2;
}
}
int[] b=new int[length];
for(int i=0;i<length;i++){
b[i]=-1;
}
for(int i=0;i<length;i++){
if(a[i]!=b[a[i]]){
b[a[i]]=a[i];
}else{
return a[i];
}
}
return -1;
}
}
思路二:遍历数组,从下标0开始,如果下标为0的元素i也为0,就遍历下标1,元素i不为0,就判断元素i和下标为i的元素j相不相等,相等说明为重复元素,输出,不相等就交换两个元素,此时下标0的元素为j,再重复判断,直到发现重复数字。
解法二:(时间复杂度为O(n),空间复杂度为O(1))
public class Test2 {
public static void main(String[] args) {
int[] a={2,3,1,0,4,5,6};
// int[] a={2,3,1,0,4,5,3};
// int[] a={2,3,1,0,2,5,3};
// int[] a={2,3,10,0,2,5,3};
// int[] a =null;
int index=findChongfu(a);
if(index==-2){
System.out.println("数组不正常");
}else if(index==-1){
System.out.println("数组中没有重复元素");
}else{
System.out.println("数组中一个重复元素为:"+index);
}
}
private static int findChongfu(int[] a) {
if(a==null||a.length<=0){
return -2;
}
int length=a.length;
for(int i=0;i<length;i++){//判断非法元素
if(a[i]<0||a[i]>length-1){
return -2;
}
}
for(int i=0;i<length;i++){
while(a[i]!=i){
if(a[i]==a[a[i]]){
return a[i];
}else{
int temp=a[i];
a[i]=a[temp];
a[temp]=temp;
}
}
}
return -1;
}
}
题目二:不修改数组找出重复的数字
在一个长度为n+1的数组里的所有数字都在1~n的范围内,所有数组中至少有一个数字是重复的,请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应输出是重复的数字2或者3。
思路:因为在1~n的范围中有n+1个数,所以肯定存在重复数字,加入把数组分成两部分,如题目中的数组长度为8,分成1~4和5~7,那么如果没有重复的话,则1~4中少于4个数,5~7中少于3个数,反之,如果数组中在1~4范围内的数字超过4个,则1~4中肯定至少有个重复数字,再将1~4分成1~2和2~3,以此类推。
解法:(时间复杂度为O(nlogn),空间复杂度为O(1))
public class Test3 {
public static void main(String[] args) {
// int a[]={2,3,5,4,3,2,6,10};
// int a[]=null;
// int a[]={2,3,5,4,3,2,6,7};
int a[]={2,1,5,3,3,2,6,7};
int index=findChongfu(a);
if(index==-2){
System.out.println("数组不正常");
}else if(index==-1){
System.out.println("数组中没有重复元素");
}else{
System.out.println("数组中的一个重复元素为:"+index);
}
}
private static int findChongfu(int[] a) {
if(a==null||a.length<=0){
return -2;
}
int length=a.length;
for(int i=0;i<length;i++){
if(a[i]<1||a[i]>length-1){
return -2;
}
}
int end=length-1;
int start=1;
while(end>=start){
int middle=(end-start)/2+start;
int count=findCount(a,start,middle);
if(end==start){
if(count>1){
return start;
}else{
break;
}
}
if(count>(middle-start+1)){
end=middle;
}else{
start=middle+1;
}
}
return -1;
}
private static int findCount(int[] a, int start, int end) {
if(a==null||a.length<=0){
return 0;
}
int count=0;
for(int i=0;i<a.length;i++){
if(a[i]>=start&&a[i]<=end){
count++;
}
}
return count;
}
}
此刻的努力是为了明天的放松。