您的位置:首页 > 其它

leetcode 287 Find the Duplicate Number

2016-03-13 13:21 344 查看
原题:

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,其中有一个数字会重复多次,用低于O(n2)的时间复杂度算法找出重复的数字,空间复杂的为O(1)。

解法:没有这些条件限制,就可以用二重循环直接找出来,或者用set/map等容器来做,正是由于这些条件限制,这题才变得有意思起来。

很不幸我没有独立解决出这道题,看题解都看了半天才明白,所以一定要用烂笔头记下来。

解法一:思路是采用了二分法+抽屉远离。首先解释一下为什么用二分法,因为O(n2)时间复杂度不能A,所以往下应该是n*logn,很容易联想到二分法,因为其复杂度为logn。

抽屉原理是说假设你有11个苹果,要放进10个抽屉,那么至少有一个抽屉里是有两个苹果的。

对应到这题,1~n的n+1个数字,有1个数字会至少重复两次。

比如取数组为{1,2,2,3,4,5},一共6个数,范围是1~5,其中位数应该是(5+1)/2 = 3,那么,如果小于等于3的数的个数如果超过了3,那么重复的数字一定出现在[1,3]之间,否则出现在[4,5]之间。以该数组为例,中位数为3,小于等于3的数一共有4个,大于3的数有两个,所以重复的数字在[1,3]之间。

代码:

int findDuplicate(vector<int>& nums)
{  
int low = 1, high = nums.size()-1;    //low和high为数字的取值范围

while(low<high)
{
int cnt = 0;     //cnt为不大于中位数的数字个数
int mid = (low + high)/2;
for(int i=0;i<nums.size();i++)
{
if(nums[i] <= mid)
cnt++;
}
if(cnt>mid)
{
high = mid;    //如果不大于mid的数字个数比mid多的话,则重复数字应该出现在[low, mid]之间
}
else
low = mid+1;   //如果不大于mid的数字个数比mid少的话,说明重复的数字出现在后半段中[mid+1,high]
}
return low;
}


解法二:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: