题目描述
解题思路
哈希表
哈希表的解题思路和 141. 环形链表 完全一样,最后找到节点的时候返回这个节点而不是返回true。
快慢指针
这边有个容易想不通的,快指针和慢指针的相遇点并不是环形链表的交点,而我们的任务是找交点。
1️⃣ 快慢指针相遇时的数学关系
假设:
- 链表头节点
head到入环点的距离为a。 - 入环点到相遇点的距离为
b。 - 相遇点到入环点的剩余环长为
c(即环的总长度L = b + c)。 - 快指针
fast走的步数是慢指针slow的 2 倍。
假设快指针 绕环 n 圈 后与慢指针相遇,则:
根据 快指针的步数是慢指针的 2 倍:
整理得到:
2️⃣ 关键推论
从上面的等式可以看出:
a(head到入环点的距离)c(从相遇点到入环点的距离)(n - 1)(b + c)(环的完整(n - 1)圈)
这意味着:
从相遇点到入环点的距离
c加上(n - 1)圈的环长 恰好等于head到入环点的距离a。
完整代码
哈希表
var detectCycle = function(head) {
// 哈希表
let set = new Set()
let p = head // 指针从head开始
while (p) { // 遍历链表
if (set.has(p)) { // 如果两个指针指向同一节点
return p // 说明找到环形链表交点,返回该节点
} else {
set.add(p) // 否则将当前节点加入Set
p = p.next // 继续遍历
}
}
return null // 遍历完链表还是没找到交点,返回null
};
快慢指针
var detectCycle = function(head) {
// 快慢指针
let slow = head // 快慢指针都从head开始遍历链表
let fast = head
while (fast && fast.next) {
fast = fast.next.next // 快指针一次走两步
slow = slow.next // 慢指针一次走一步
if (fast === slow) { // 如果快慢指针相遇
let slow = head // 将慢指针移动到头节点
while (slow !== fast) { // 循环遍历 直到快慢指针再次相遇
slow = slow.next // 快慢指针每次都各走一步
fast = fast.next
}
return ptr // 快慢指针相遇,返回当前指向的节点
}
}
return null // 遍历完链表还是没找到交点,返回null
};