这道题是典型的判断环形链表的题,与141. 环形链表,142. 环形链表 II。属于同一类,都是快慢指针先找到相遇点,再从相遇点开始,slow从0开始,再走一遍,就是重复点(相交起始点)。这是【Floyd 判圈算法】
假设环长为 L,从起点到环的入口的步数是 a,从环的入口继续走 b 步到达相遇位置,从相遇位置继续走 c 步回到环的入口,则有 b+c=L,其中 L、a、b、c 都是正整数。根据上述定义,慢指针走了 a+b 步,快指针走了 2(a+b) 步。从另一个角度考虑,在相遇位置,快指针比慢指针多走了若干圈,因此快指针走的步数还可以表示成 a+b+kL,其中 k 表示快指针在环上走的圈数。联立等式,可以得到
2(a+b)=a+b+kL
解得 a=kL−b,整理可得
a=(k-1)L+(L-b)=(k-1)L+c
从上述等式可知,如果慢指针从起点出发,快指针从相遇位置出发,每次两个指针都移动一步,则慢指针走了 a 步之后到达环的入口,快指针在环里走了 k-1 圈之后又走了 c 步,由于从相遇位置继续走 c 步即可回到环的入口,因此快指针也到达环的入口。两个指针在环的入口相遇,相遇点就是答案。
class Solution {
public int findDuplicate(int[] nums) {
int slow =nums[0], fast = nums[nums[0]];
while(slow!=fast){
slow = nums[slow]; // 慢指针走一步
fast = nums[nums[fast]]; //快指针走两步
}
slow = 0; // 这里解释一下,之前相遇意思是快指针对慢指针扣圈了,一定存在相交
while(slow!=fast){ //这个循环的意思是从相遇点开始,再有c步,快慢指针同时在环形入口相遇
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}