Leetcode287 寻找重复数

281 阅读2分钟

这道题是典型的判断环形链表的题,与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 步即可回到环的入口,因此快指针也到达环的入口。两个指针在环的入口相遇,相遇点就是答案。

image.png

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;
    }
}