这个数组可以形成有环的单向链表,数组下标是当前点,数组值是指向下一节点的指针
假设环外长d,环长l,相碰处距汇点x
则fast = d+l+x,slow = d+x,且fast = 2slow
解得x = l - d,即slow再走d步就是汇点。
第一次初始化假设f和s都各先走了一步,
s= 0 , s = nums[s] 即 s = nums[0]
f = 0, f = nums[nums[f]] 即 f = nums[nums[0]]
故f第二次初始化为0
/*
* @lc app=leetcode id=287 lang=cpp
*
* [287] Find the Duplicate Number
*/
// @lc code=start
class Solution {
public:
// 因为值都在数组下标范围内,所以刚好可以形成单向链表
// 重复值会形成链表的环
int findDuplicate(vector<int>& nums) {
int N = nums.size();
int s = nums[0]; // 一个步长为1
int f = nums[nums[0]]; // 一个步长为2
// 第一次循环,若有环,会在环内l-d处相遇
for(int i=0;i<N;i++){
if(s == f) break;
s = nums[s];
f = nums[nums[f]];
}
// 第二次循环,f和s同时1步长走d步,会再次碰到就是汇合处
f = 0; // f从0开始才是d步,从nums[0]开始是d-1步,如上
for(int i=0;i<N;i++){
if(f == s) break;
f = nums[f];
s = nums[s];
}
return s;
}
};
// @lc code=end