142. 环形链表 II
代码
ts
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function detectCycle(head: ListNode | null): ListNode | null {
let a = head;
let b = head;
while(b && b.next){
a = a!.next;
b = b.next.next;
if(a === b){
let p = head;
while(p !== a){
p = p!.next;
a = a!.next;
}
return a;
}
}
return null
};思路
使用快慢指针找到环的入口节点,分为两个阶段:
阶段一:检测是否有环
- 初始化快慢指针
a和b都指向head - 慢指针每次移动一步,快指针每次移动两步
- 如果有环,两指针必定相遇;如果无环,快指针会到达链表末尾
阶段二:找到环的入口
- 当快慢指针相遇后,将一个指针
p重新指向head - 让
p和慢指针a同时以相同速度(每次一步)移动 - 当
p和a相遇时,相遇点就是环的入口节点
数学原理
设链表头到环入口的距离为
- 慢指针走过的距离:
- 快指针走过的距离:
(多走了 圈) - 因为快指针速度是慢指针的 2 倍:
- 化简得:
这说明从头节点到环入口的距离
- 时间复杂度
,其中 是链表的长度 - 空间复杂度