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.
题目设定的问题是N+1个元素都在[1,n]这个范围内。这样我们可以用那个类似于 ‘缺失的第一个正数’ 这种解法来做,但是题意限制了我们不能修改原数组,我们只能另寻他法。也就是本编题解讲的方法,将这个题目给的特殊的数组当作一个链表来看,数组的下标就是指向元素的指针,把数组的元素也看作指针。如0是指针,指向nums[0],而nums[0]也是指针,指向nums[nums[0]].
这样我们就可以有这样的操作
int point = 0; while(true){ point = nums[point]; // 等同于 next = next->next; }
链表中的环
假设有这样一个样例:[1,2,3,4,5,6,7,8,9,5]。如果我们按照上面的循环下去就会得到这样一个路径: 1 2 3 4 5 [6 7 8 9] [6 7 8 9] [6 7 8 9] . . .这样就有了一个环,也就是6 7 8 9。point会一直在环中循环的前进。
这时我们设置两个一快(fast)一慢(slow)两个指针,一个每次走两步,一个每次走一步,这样让他们一直走下去,直到他们在重复的序列中相遇,
1 class Solution { 2 public: 3 int findDuplicate(vector<int>& a) { 4 int slow = 0; 5 int fast = 0; 6 while(true) { 7 fast = a[a[fast]]; 8 //fast = fast->next->next; 9 slow = a[slow]; 10 if(fast==slow) break; 11 } 12 fast = 0; 13 while(true) { 14 fast = a[fast]; 15 slow = a[slow]; 16 if(fast==slow) return fast; 17 } 18 return -1; 19 } 20 };