在含环的问题中,存在一些关键性的结论,在解决问题时非常有帮助,下面是一些相关的总结。
1.判断链表是否有环
结论:一个速度为1的low指针和一个速度为2的fast指针同时从头向前走,如果其中fast指针为None,那么则为无环,如果两个只能指向的元素相等,那么链表有环。
2.判断链表的环入口节点
结论:函数一样的双指针进行遍历,如果fast指针为None,那么则为无环。如果两个指针指向的的元素相同,那么这个节点到链表入口点的长度和链表头到链表入口点的长度相等。
推导过程:
设链表头到入口节点的长度为a
链表入口节点到相遇节点的长度为b
相遇节点到链表入口节点的长度为c
那么因为fast的速度为2,low的速度为1,因此可以认为low入环时走在前面,每次fast和low之间的距离缩小1,因此,必定会在第一圈完成之前相遇。所以有
low 在环内位置: (a+b)-a mod (b+c) -> b mod (b+c)
fast 在环内位置:2(a+b)-a mod (b+c) -> a+2b mod (b+c)
二者应该相等,因此得出 a+b mod (b+c) = 0 即a = c
利用这个结论,我们可以先判断判断链表是否有环,如果有环,那么先找到相间的节点,然后再用一个新指针从头开始以速度为1和low指针从相交节点同时开始遍历,当两个点相交的节点即为环入口节点。
例题:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回
null
.
1 | def detectCycle(head): |
3.变形型题目
有一类题目不会明显的说让解决环的问题,但是使用环来解决,往往会起到意想不到的效果。
例题:编写一个程序,找到两个单链表相交的起始节点。
1 | def getIntersectionNode(headA, headB): |
这道题利用了和上一道题目完全一样的规律解决