本文解决一下几个问题
- 使用快慢指针判断链表中的环
- 快慢指针有多中实现细节,本文采用统一的方式来处理这些细节,减少心智负担
- 逻辑中的链表(指针的指向与函数的映射没有本质差别,只是空间与时间的交换)
- 如何寻找找到环所在的位置
链表是否有环
思路:使用快慢指针,快指针每次走两步,慢指针每次走一步,如果有环,那么快指针一定会追上慢指针,如果没有环,那么快指针一定会走到链表的末尾。
function hasCycle(head) {
if (head == null || head.next == null) return false
let slow = fast = head
do {
slow = slow.next
fast = fast.next.next
} while (fast && fast.next && fast !== slow)
// 如果有环,那么快指针一定会追上慢指针,如果没有环,那么快指针一定会走到链表的末尾
return fast != null && fast.next != null
}
快乐树(逻辑思维中的链表)
function isHappy(n) {
let slow = fast = n
do {
slow = getNext(slow)
fast = getNext(getNext(fast))
} while (fast !== 1 && getNext(fast) !== 1 && fast !== slow)
// 快指针走到 1 则说明没有环
if (fast === 1 || getNext(fast) === 1) return true
return false
}
function getNext(num) {
return (num + '').split('').reduce((prev, curr) => prev + curr * curr, 0)
}
链表的环在何处
function detectCycle(head) {
if (head == null || head.next == null) return null
let slow = fast = head
do {
slow = slow.next
fast = fast.next.next
} while (slow !== fast && fast && fast.next)
// 如果快节点走到了末尾,则证明没有环
if (fast == null || fast.next == null) return null
// 任意选择一个点回到链表头部
slow = head
while (slow !== fast) {
slow = slow.next
fast = fast.next
}
// 此时快慢节点相遇在出现环的位置
return fast
}