287. Find the Duplicate Number
Description:
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.
Solution:
一、题意理解
给定一个长度为n+1的数组,每一个数都是在1~n之间,那么至少会有一个数是重复的。现在假设只有一个重复的数,则找出这个数。
注意:
1、不能修改原数组(数组是只读的)
2、空间复杂度为O(1)
3、时间复杂度需要小于O(n^2)
4、只有一个重复的数字,但它可能重复的不止一次。
二、分析
1、一不能修改原数组,二空间复杂度为O(1),所以无法通过计数的方式来查找这个数,只能通过遍历查找的方式。说起查找,普通方法就是针对数组中的每一个数,都再遍历一次数组看是否有重复的数,就算优化后,从当前数的下一个数开始搜索,时间复杂度依然为O(n^2)。
2、查找算法中,除了所谓Hash映射之外,二分查找是效率最高的,那么我们是否可以利用二分查找呢。根据数组的特点,对于一个数字 i ,设数组中 <= i 的数的数量为count,那么如果count <= i,那么肯定有一个比 i 大的数重复,使得一个比i小的数被“冲”掉了,那么这个数肯定大于i。否则,这个数肯定<=i。根据这个特点,我们可以以1~n为范围做二分查找,令i = (1 + n) / 2,每一次都计算count (where num<=i)来缩小一半的查找范围,知道最后能查找到这个重复的数。
3、空间复杂度为O(1),时间复杂度为O(nlog(n)),代码如下:
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int begin = 1;
int end = nums.size() - 1;
int count, mid;
vector<int>::iterator it;
while(begin < end)
{
mid = (begin+end) / 2;
count = 0;
for(it = nums.begin(); it != nums.end(); ++it)
{
if(*it <= mid)
count++;
}
if(count <= mid)
begin = mid+1;
else
end = mid;
}
return end;
}
};