关于链表是否有环,其实是一系列问题,主要包括以下几个:
使用快慢指针fast和slow,fast每次走两步,slow每次走一步,如果有环,肯定会相遇,如果没有,则指针fast遇到NULL退出。追及相遇问题。
在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步。在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长。
设从第一次相遇到第二次相遇,设slow走了len步,则fast走了2*len步,相遇时多走了一圈:
环长=2*len-len
第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R。
第一次相遇时,slow走的长度 S = LenA + x;
第一次相遇时,fast走的长度 2S = LenA + n*R + x;
所以可以知道,LenA + x = n*R; LenA = n*R -x;
上述2中求出了环的长度;3中求出了连接点的位置,就可以求出头结点到连接点的长度。两者相加就是链表的长度。
不管快指针走多少步,只要有环就会与慢指针相遇,因为慢指针每次都走一步。但是如果快指针每次走三步以上,就会导致上述公式不成立。比如说快指针每次走三步,则公式变为:
第一次相遇时,slow走的长度 S = LenA + x;
第一次相遇时,fast走的长度 3*S = LenA + n*R + x;
所以可以知道,2*LenA + 2*x = n*R; LenA = n*R/2 -x;
举例:头结点之后就是环的入口,环除了入口还有一个节点,fast每次走三步,slow每次走一步,第一次会在环的入口相遇,分别从第一次碰撞点Pos、头指针head开始走,无法相遇。
参考文献:
https://www.cnblogs.com/xudong-bupt/p/3667729.html
原文:https://www.cnblogs.com/yaochunhui/p/14128777.html