首先,判断一个单链表是否有环。网上有很多解法就是设置两个指针fast,slow分别指向链表头部,然后同时向后遍历。fast步长为2即每次走两步,slow每次走一步。如果fast走到链表尾部则肯定没有环,因为如果有环肯定是如下图所示的样子。
如果fast和slow相遇则有环。有没有可能在有环的情况下fast和slow永远不相遇呢?假设在某个时间slow走过的路程为S而且slow已经在环上了,则fast走过的为2S。因为fast是速度是slow的两倍。假设环的长度为L,fast和slow不相遇的条件就是(2S - S) % L != 0永远成立,因为fast和slow相遇即在某一时刻fast比slow多走过了n(n>=1)圈,(2S - S) % L == S % L != 0是不是会永远成立?明显不会,因为S每次增加1,总有一天会等于0成立。
现在假设已经知道了有环,来求环的入口点。
如上图所示,我们先作如下的假设:
链表起点为A点;
环的入口为B点;
fast和slow的相遇点为C;
链表的方向为顺时针;
A到B的距离为X;
B到C的距离为Z;
C到B的距离为Y。
则有如下的结果成立:
1. X + Z = S;
2. X + Z + nL = 2S;
3. Y + Z = L;
即X + Z + nL = 2X + 2Z -> X = nL - Z = nL - (L - Y) = (n - 1)L + Y。最后的结果就是X = (n - 1)L + Y,其中n>=1。也就是说从A和C点同时出发,以步长为1遍历链表,那么在C处出发的指针在多走了n-1圈之后与从A出发的指针在B处相遇。也就是说两个指针指向同一个节点的时候这个点就是环的入口点。