问题描述
Given an array nums containing n+1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Note:
- You must not modify the array (assume the array is read only).
- You must use only constant, O(1) extra space.
- Your runtime complexity should be less than O( n2 ).
- There is only one duplicate number in the array, but it could be repeated more than once.
该问题中文简单描如下:
n+1个整数组成的数组,每个整数范围在1到n之间(保证至少有一个数重复),假设只有一个重复数字,但可以重复多次
算法要求:
数组只读、空间复杂度常数阶、时间复杂度小于平方阶
思路:
假设数组长度为nlen,可以设定下界low=1,上界high=nlen,中间值mid=(low+high)/2,从理论上讲,如果数字没有重复,mid值和实际算出来数组的中值应该是一样的(最大值不大于数组长度,也就是没有条数字)。但由于问题中最大值不会大于数组长度,保证了 一定会有一个重复数字,利用mid可以把数组分成两部分,一部分的值小于等于mid,另一部分的值大于mid,计算出第一部分的个数count,如果第一部分的个数大于mid,可以知道重复的数字是在这一部分里,否则在另一部分里。该部分可以得到新的low值和high值,比如在第一部分,low不变,high=mid,这两个值是为了得到新的mid值服务的,(low和high只是数的序号,不是真正的数组值)然后可以更新low和high的值,以此类推。
下面举两个例子:
(1)数组{1,4,2,4,2}
循环条件:low
<
high
初始: low=1,high=5,mid=3,count=3
第一次:判断count
≥
mid
low=1,high=mid=3,mid=2,count=3
第二次: 判断count
≥
mid
low=1,high=mid=2,mid=1,count=1
第三次: 判断:count
<
mid
low=mid+1=2,high=2
循环结束
(2)数组{1,4,4,2,4}
循环条件:low
<
high
初始: low=1,high=5,mid=3,count=2
第一次:判断count
<
mid
low=mid+1=4,high=5,mid=4,count=3
第二次: 判断count
≥
mid
low=4,high=mid=4
循环结束
上述设计思路满足算法要求,时间复杂度o(
nlog2n
)
注:
(1)low更新是为mid+1,否则会死循环(第一个例子)
(2)count的计算值是小于等于mid的数的个数,不是low和mid之间数值的个数。
c++程序如下:
class Solution {
public:
int findDuplicate(vector<int>& nums){
int n = nums.size();
int low = 1;
int high = n;
int mid;
while(low<high)
{
mid = (low + high) / 2;
if (count(low,high,nums)<=mid)
low=mid+1;
else
high= mid;
}
return low;
}
int count(int low, int high, vector<int>& nums)
{
int count0 = 0;
int n = nums.size();
int mid = (low + high) / 2;
for (int i = 0;i <n;i++)
{
if (nums[i] <=mid )
count0++;
}
return count0;
}
};
关联问题:二分查找