思路1
遍历链表,第一次访问每个节点都给节点加个标记,当第二次走到环入口,发现有标记,就直接返回
思路2: 参考代码随想录
使用快慢指针,快指针每次走2个节点,慢指针走1个节点
如下图 出x就是求出了环入口
相遇时slow走了:x+y
相遇时fast走了: x+y+n(y+z)
因为fast步长是slow的2倍,所以
2(x+y )= x+y+n(y+z)
x + y = n(y+z)
x = n(y+z) - y
看下边的图,n(y+z)就是fast从相遇点到相遇点绕了n圈,
n(y+z)-y解释一下:绕了n圈 减去y , 其实就是快指针从从相遇点到相遇点绕了n-1圈,最后一圈只走了z那一部分不走y了
既然x的长度等于绕了n圈减去y的长度,那么slow从头节点出发,fast从相遇点出发,每次移动一个节点,走了x个节点后, 就都到达了环入口,也就是他们相遇了,所以可以在代码中判断 如果相遇,相遇点就是环入口
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle2(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 遍历链表,第一次访问每个节点都给节点加个标记,如果有标记 说明当前节点是环形节点的入口
cur = head
while cur:
try:
getattr(cur, "flag")
return cur
except:
setattr(cur, "flag", True)
cur = cur.next
return None
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 使用快慢指针,快指针速度是慢指针的2倍
# 快指针走到相遇点(但还没相遇,慢指针还在前面),剩下需要走k的距离,相遇点到环入口点的距离=k-环入口点到相遇点的距离(相遇点到环入口点的距离 可能包含了多个环)
# 慢指针从head走到相遇点距离是k,head到环入口点的距离=k-环入口点到相遇点的距离
# 所以相遇点到环入口点的距离=head到环入口点的距离
# 所以当两个指针相遇时,slow指针回到head fast指针不变,他们以相同的速度前行,走到环入口点经过的距离是相等的,即相遇时所在位置是环入口点
fast = slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
slow = head # 也可以吧fast指向head 都行
while fast != slow:
fast = fast.next
slow = slow.next
return fast
return None