51 数组中重复的数字
Posted shareidea94
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51 数组中重复的数字相关的知识,希望对你有一定的参考价值。
题目要求:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组2,3,1,0,2,5,3,那么对应的输出是第一个重复的数字2。
1 public class Solution 2 // Parameters: 3 // numbers: an array of integers 4 // length: the length of array numbers 5 // duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation; 6 // Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++ 7 // 这里要特别注意~返回任意重复的一个,赋值duplication[0] 8 // Return value: true if the input is valid, and there are some duplications in the array number 9 // otherwise false 10 public boolean duplicate(int numbers[],int length,int [] duplication) 11 12
思路一:最好的解法
此大法利用了哈希的特性,但不需要额外的存储空间。 因此时间复杂度为O(n),不需要额外空间!
因为列表总共有n个元素,所有元素可能取到的元素有0~n-1,共n种。如果不存在重复的数字,那么排序后数字i将会出现在下标为i的位置。现在让我们重新扫描数组,
- 当扫描到下标为i的数字时,首先比较这个数字(记为m)与i是否相等:
- 如果是,继续扫描下一个元素,
- 如果不是,则再拿它与第m个数字比较:
- 如果它和第m个数字相同,就找到了一个重复的元素;
- 如果不同,就将m与第m个数字互换。接下来继续重头开始,重复换这个比较。
1 public class Solution 2 public boolean duplicate(int numbers[],int length,int [] duplication) 3 //考虑特殊情况,并判断数组是否合法(每个数都在0~n-1之间) 4 if(length<=0||numbers==null) return false; 5 for(int i=0;i<length;i++) 6 if(numbers[i]<=0||numbers[i]>length-1) 7 return false; 8 9 //关键代码来了 10 for(int i=0;i<length;i++) 11 while(numbers[i]!=i) 12 if(numbers[i]==numbers[numbers[i]]) 13 duplication[0] = numbers[i]; 14 return true; 15 16 //交换numbers[i]和numbers[numbers[i]] 17 int temp = numbers[i]; 18 numbers[i] = numbers[temp]; 19 numbers[temp] = temp; 20 21 22 return false; 23 24
居然能找到错误,开森
/* 一开始交换写错了写成了这:
int temp = numbers[i];
numbers[i] = numbers[numbers[i]];
numbers[numbers[i]] = temp;
于是就错了...
*/
思路二:利用HashMap或者HashTable
不建议
- 由于所有元素值是有范围的,因此可以用一个长度为n的数组,下标表示序列中的每一个值,下标对应的值表示该下标出现的次数。
- 只需扫描一次原序列,就统计出所有元素出现的次数;
- 再扫描一次哈希数组,找到一个出现次数大于1的值即可。
这种方法时间复杂度和空间复杂度都为O(n)。
1 public boolean duplicate(int array[],int length,int [] duplication) 2 if ( array==null ) return false; 3 4 // 判断数组是否合法(每个数都在0~n-1之间) 5 for ( int i=0; i<length; i++ ) 6 if ( array[i]<0 || array[i]>length-1 ) 7 return false; 8 9 10 11 // key step 12 int[] hash = new int[length]; 13 for( int i=0; i<length; i++ ) 14 hash[array[i]]++; 15 16 for(int i=0; i<length; i++) 17 if ( hash[i]>1 ) 18 duplication[0] = i; 19 return true; 20 21 22 return false; 23
另外一个相似的题目
在一个长度为n+1的数组里的所有数字都在1~n范围内,所以数字中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改数组。例如,如果输入长度为8的数组2,3,5,4,3,2,6,7,那么对应的输出是重复的数字2或3。(n+1个元素,n种可能的取值)
最优解法:避免使用O(n)的辅助空间。我们把取值空间[1,n]从中间的数字m分为两部分,前面一部分为1~m,后面一部分为m+1~n。如果数组中元素落在前面一部分的元素个数多于m个,那么数组中重复的元素一定落在前半区间;否则,数组中重复的元素一定落在后半区间。然后,我们可以继续将包含重复元素的区间一分为二,直到找到一个重复的元素。
以上是关于51 数组中重复的数字的主要内容,如果未能解决你的问题,请参考以下文章
给定一个只包含正整数的非空数组,返回该数组中重复次数最多的前N个数字 ,返回的结果按重复次数从多到少降序排列(N不存在取值非法的情况)