解题思路
这题也是一道非常经典的链表题,双指针伺候。
算法过程
-
先初始化两个快慢指针
slow
,fast
位于链表头 -
随后将
slow
指针每轮走一步,fast
指针每轮走两步,一直走到它们相遇,当然也会遇到无环链表,下面对两种情况进行逐个分析。-
如果
fast
指针走到了链表的末尾not (fast and fast.next)
,说明链表无环,直接返回None -
如果遇到
fast == slow
,说明两指针相遇了。此时我们不知道两个指针在环中走了几圈,也不知道在环中走了几步,接下来我们在对这种相遇的情况进行详细分析。假设链表有a
+b
个节点,a
指的是链表头部到环入口的节点数,b
指的是链表环的节点数。-
已知
fast
指针走的步数是slow
的2倍,设两指针分别走了f
,s
步,记作f=2s
-
在相遇时
fast
肯定比slow
多走了n
圈,n
未知,记作f = s + nb
->2s = s + nb
->s = nb
,f = 2nb
, 即fast
走了2n
环步数,slow
走了n
环步数。 -
从
s = nb
, 我们可以知道相遇时slow
指针走了nb
个步数,那么不管n
为多少,它只要再走a
步,必然走到了环的入口处。知道了这点我们接下来就好操作了。
-
-
-
此时我们将
fast
指针放到链表头处,两个指针每轮走一步,直到它们相遇。此时fast
指针走了a
步,slow
也走了a
步,那么这个节点必然是环的入口。
代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
if not head or not head.next: return None
slow, fast = head, head
while True:
if not (fast and fast.next): return
slow, fast = slow.next, fast.next.next
if slow == fast: break
fast = head
while fast != slow:
slow, fast = slow.next, fast.next
return fast