一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
解1:哈希表
哈希表可以用O(1)的事件复杂度完成 添加或者查询操作。这里可以通过哈希表判断当前节点是否已保存,如果已存在表明之前出现过:有环,反之则没有。
const hasCycle = function(head: ListNode | null): boolean {
const set = new Set<NodeList>()
let cur = head
while(cur) {
// 判断是否已存在
if (!set.has(cur)) {
set.add(cur)
} else {
// 表明之前已出现过,有环
return true
}
cur = cur.next
}
// 正常退出,没有出现重复节点,无环
return false
}
在前端面试中经常被问到深拷贝的实现,深拷贝中有一个陷阱:循环引用。而哈希表(Map,考虑性能的话可以使用WeakMap,没有引用时自动回收)可以用来解决循环引用的问题,跟这里的逻辑是相似的。
解2: 快慢指针
一只不打盹的兔子和乌龟赛跑,肯定甩乌龟好几条街。
将指针同时指向头节点,然后慢指针每次走一步,快指针每次走两步,这样如果有环的话,快慢指针必然相遇,否则的话fast应该会变成null。
const hasCycle = (head: ListNode | null): boolean => {
if (head === null) return false
let slow: ListNode | null = head, fast: ListNode | null = null
if (slow.next) {
fast = slow.next.next
}
// 如果fast和slow相同,或者fast不存在退出循环
while(slow && fast && slow !== fast) {
slow = slow.next
fast = fast.next
if (fast) {
fast = fast.next
}
}
// 如果是因为相同退出的表明相遇则有环
return slow === fast
}