题目:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
思路: 快慢指针 + 同步指针 (参考1)
有环 3→2→0→4→2 无环 3→2→0→4
p1走一步:3 2 0 4 2 0 4 p1走一步: 3 2 0 4
p2走两步:3 2 0 4 2 0 4 2 0 4 2 0 4 p2走两步:3 2 0 4
假设:
链表头部到链表入口 有 a 个节点(不计链表入口节点)(即例子中3)
链表环长 b (即例子中的 2 0 4)
慢指针p1 在第一次相遇时 走过的路为 s(3 2 0)
快指针p2 在第一次相遇时 走过的路为 f (3 2 0 4 2 0)
第一次相遇s和f的关系如下:
快指针一定比慢指针多走了n圈: f - s = nb 综合两个式子可得 s = nb (s=3)
快指针的速度是慢指针的2倍: f = 2s f = 2nb (f=6)
二次相遇(p与慢指针同步走):
当指针 p 从头部开始走时,走过的路程 k=0 路过 入口节点时,走过的路 k = a (1)
慢指针此时走过的路 s=nb s = a+nb(4)
此时返回 k 即为入口下标 P 或者 p1即为入口节点
改进: 可以用 p2代替p
复杂度: 时间复杂度 O(n) 空间复杂度 O(1)
代码:
def detectCycle(head):
# 当列表为空 或者 只有一个元素时
if not head or not head.next:
return None
mark = 0
p1, p2 = head, head
while p2 and p2.next:
p1 = p1.next
p2 = p2.next.next
if p1 == p2:
mark = 1 # 设置标志位
break
if mark == 0:
return None
p2 = head
while p1 != p2:
p1 = p1.next
p2 = p2.next
return p1