在长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。
思路:
一、把1~n的数字从中间的数字m分成两部分,前面一半为1 ~m,后面一半为m+1 ~ n;
二、若1 ~ m的数字的数目超过m,那么这一半的区间里一定包含重复的数字;否则另 一半m+1 ~n的区间里一定包含重复的数字。
三、继续把包含重复数字的区间一分为二,直到找到一个重复的数字。
时间复杂度:O(nlog(n))
空间复杂度:O(1)
#include <iostream>
using namespace std;
int countRange(const int* nums,int len,int start,int end){
if(nums==nullptr) return 0;
int count=0;
for(int ii=0;ii<len;ii++){
if(nums[ii]>=start&&nums[ii]<=end) count++;
}
return count;
}
int getDuplication(const int* nums,int len){
if(nums==nullptr||len<=0) return -1;
for(int ii=0;ii<len;ii++){
if(nums[ii]<1||nums[ii]>len-1){
return -1;
}
}
int start=1;
int end=len-1;
while(end>=start){
int mid=((end-start)>>1)+start;//找出中间元素
int count=countRange(nums,len,start,mid);
if(start==end){
if(count>1) return start;
else break;
}
if(count>(mid-start+1)){ //mid-start+1 意味着计算区间内元素的个数
end=mid;
}else{
start=mid+1;
}
}
return -1;
}
int main(){
//int nums[]={2,3,5,4,7,2,6,7,7};
int nums[]={1,1,9};
int res=getDuplication(nums,sizeof(nums)/sizeof(int));
cout<<res<<endl;
}