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.
=============================================================================
题目链接:https://leetcode.com/problems/find-the-duplicate-number/
题目大意:给定一个长度为n+1的数组,其中数组中的数值范围都在1-n之间,而且数组中有且只有一个数值多次出现(出现的次数>=2),求出这个多次出现的数值。
要求:不能修改数组,只可读、空间复杂度为O(1)、时间复杂度不超过O(N^2)。
思路:利用二分+搜索求解。
1、已知miner = 1,maxer = n 。
2、mid = ( miner + maxer ) / 2 ,统计数组中在[miner,mid]范围内的个数sum。
3、当sum <= mid - miner + 1 时,说明该数值不在[miner,mid]范围内,miner = mid + 1。
4、否则说明该数值在[miner,mid]范围内,maxer = mid。
5、miner == maxer时就是我们要求的结果。
综上,二分时间复杂度为O(logN),搜索时间复杂度为O(N),所以总的时间复杂度为O(N*logN)。
参考代码:
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int n = nums.size() ;
int miner = 1 , maxer = n ;
while ( miner < maxer )
{
int mid = ( miner + maxer ) / 2 , sum = 0 ;
for ( int i = 0 ; i < n ; i ++ )
if ( nums[i] >= miner && nums[i] <= mid )
sum ++ ;
int num = mid - miner + 1 ;
if ( sum <= num )
miner = mid + 1 ;
else
maxer = mid ;
}
return miner ;
}
};