问题描述:
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(n*logn),空间O(1)。
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
for (int i=0; i<n-1; i++){
if(nums[i] == nums[i+1]) return nums[i];
}
return 0;
}
};
显然不能满足要求,肯定有O(n)的做法,但是它这个重复元素不止出现了一次,想了半天也没想出来了,翻了一下solution,也看了一下人家博客才看懂。
根据题目,包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。
对应地,如果设计一个指针 i,每次移动到 nums[i],由于存在重复整数,一定存在节点入度大于 1,即该指针的遍历轨迹中存在环,且重复整数为环的入口。
因此可以设计两个运动速度不同的快慢指针,经过一段时间后它们会在环中相遇。
之后寻找环入口的思路与 leetcode【141、142】Linked List Cycle、Linked List Cycle II【c++,双指针法,技巧,时间94%,空间100%】相同,将其中一个指针退回到数组起点,与另一相遇处的指针以相同速度向前遍历,相遇处即为重复整数。
时间89.4%
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int fast = nums[0], slow = nums[0];
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while(fast != slow);
// cout<< fast <<endl;
slow = nums[0];
while (fast != slow){
slow = nums[slow];
fast = nums[fast];
}
return fast;
}
};