287. Find the Duplicate Number
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.
Example 1:
Input: [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2] Output: 3
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
解题思路:
这个题目要求比较多,用O(1)的空间复杂度,这也就意味着我们不能使用哈希。这个题目有个巧妙地地方,就是这n个数的范围是固定的,这也就意味着可以进行枚举。最坏的情况O(n^2),这里可以使用二分法查找(因为这n个数字是从1到n的有序数列)。首先计算二分法的终点mid,然后遍历整个nums数组,如果小于等于mid的数字个数小于等于mid,则意味要求的数字在mid的右边,否则判断一下当前的这个mid是不是在数组中有超过两个,如果是则return mid。没有的话继续进行二分查找。
// class Solution {
// public:
// int findDuplicate(vector<int>& nums) {
// unordered_map<int, int> map;
// for(int i=0; i<nums.size(); i++) {
// map[nums[i]] += 1;
// //printf("%d, %d\n", nums[i], map[nums[i]]);
// if(map[nums[i]]==2) {
// //printf("%d\n",nums[i]);
// return nums[i];
// }
// }
// return -1;
// }
// };
class Solution {
public:
int findDuplicate(vector<int>& nums) {
unordered_map<int, int> map;
int left = 1, right = nums.size();
int mid;
int cnt;
int cntD;
while(left<right) {
mid = (left + right) / 2;
cnt=0;
cntD=0;
for(int i=0; i<=nums.size()-1; i++) {
if(nums[i]<=mid) {
cnt++;
}
if(nums[i]==mid) cntD++;
}
if(cntD>=2) {
return mid;
}
if(cnt<=mid) {
left = mid+1;
}
else {
right = mid;
}
}
return -1;
}
};