問題描述:
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;
}
};