面试题3(二):不修改数组找出重复的数字
// 面试题3(二):不修改数组找出重复的数字
// 题目:在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至
// 少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的
// 数组。例如,如果输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},那么对应的
// 输出是重复的数字2或者3。
解题思路:
不能修改数组,可以创建一个长度为n+1的辅助数组,空间复杂度为O(n)。
如果用时间换空间的话,可以使用二分查找的思想。
元素范围为1~n,但是有n+1个元素,说明有某个数字重复了。
以中间数字m为界限,分成两部分,1~m和m+1~n。
如果1~m的元素个数超过了m,说明重复元素在前半部分,再次划分1~m。
重复此过程,直到最后找出重复元素。
伪代码:
if(输入参数无效) return -1;
int start=1; int end=length-1; while(start<=end){ int middle=区间中点; int count=start到middle之间元素个数; if(区间上下限相等){ if(count大于1) return start; else return -1; } if(count>(middle-start+1)) end=middle; else start=middle+1; } return -1;
c/c++代码:
int getDuplication(const int* numbers,int length){ //校验输入参数的有效性 if(numbers==nullptr||length<0){ return -1; } for(int i=0;i<length;i++){ if(numbers[i]<1||numbers[i]>length-1){ return -1; } } //二分查找重复元素 int start=1; int end=length-1; while(end>=start){ int middle=((end-start)>>1)+start; int count=countRange(numbers,length,start,middle); //区间上下限相等 if(end==start){ //元素数量大于1,成功查找 if(count>1) return start; else break; } //区间上下限不等,继续二分查找 if(count>(middle-start+1)) end=middle; else start=middle+1; } return -1; } //获取区间元素个数 int countRange(const int* numbers,int length,int start,int middle){ if(numbers==nullptr||length<0){ return -1; } int count=0; for(int i=0;i<length;i++){ if(numbers[i]>=start&&numbers[i]<=middle) count++; } return count; }
参考资料: