一日一练: 环形链表

107 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

leetCode 141.给你一个链表的头节点 head ,判断链表中是否有环。

解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,没有引用时自动回收)可以用来解决循环引用的问题,跟这里的逻辑是相似的。

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
}