287. Find the Duplicate Number(Medium)
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(1)空间复杂度,小于O(n^2)的时间复杂度,重复的数字可以出现多于2次。
分析:
amazing 啊! 一道非常有分量的题目,题设简单,但是为了追求更优解是值得花时间的!
1. 最暴力的解法就是直接穷举,但是时间复杂度是O(n^2),不满足题意。
2. 要把时间复杂度降下来,很自然就能想到O(nlogn)的二分查找,在[1,n]范围内用二分枚举答案,记为mid。遍历数组,如果比mid小的数字超过mid个,那答案就会落在[1,mid];否则,则答案落在(mid,n];解法也没什么难度,也好理解,直接上代码把:
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int len = nums.size()-1;
int right = len, left = 1;
int mid,count;
while (left < right){
mid = (left + right) / 2;
count = 0;
for (int i = 0; i < len+1 ; i ++)
if (nums[i] <= mid) count++;
if (count > mid) right = mid;
else left = mid + 1;
}
return left;
}
};
3. 实在想不到…这题真的还能有O(n)复杂度的解法。使用的是快慢指针的思想,原理我直接贴我看的题解和帖子吧,不再赘述一遍。
解法用到了快慢指针找链表闭环问题的思想(
http://bookshadow.com/weblog/2015/07/10/leetcode-linked-list-cycle-ii/)
针对这道题的这个构造简直惊为天人!
英文看得晕的,还有一个中文翻译版的:
学习了学习了。