# 141-环形链表

# 题目描述

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

进阶:

你能用 O(1)(即,常量)内存解决此问题吗?

# 解题思路

# 方法一:哈希表

思路:

  • 最容易想到的方法是遍历所有节点,每次遍历到一个节点时,判断该节点此前是否被访问过。
  • 具体地,我们可以使用哈希表来存储所有已经访问过的节点。每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到我们遍历完整个链表即可。

代码:

var hasCycle = function(head) {
    // 1. 维护一个哈希表
    // 2. 遍历链表,每次判断当前节点是否在哈希表中,若不在,则加入到哈希表;若在,说明有环,返回true

    let map = new Map();
    let p = head;
    while(p) {
        if (map.has(p)) return true;
        map.set(p, p);
        p = p.next;
    }
    
    return false;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

# 方法二:快慢指针

思路:

  • 两个人在操场上的起点同时起跑,速度快的人一定会超过速度慢的人一圈
  • 用一快一慢两个指针遍历链表,如果指针能够相遇,那么就说明链表有环 参考 (opens new window)

代码:

var hasCycle = function(head) {
    if (!head) return false;

    // 解题思路:
    // 1. 维护一快一慢两个指针
    // 2. 遍历链表,每次慢指针移动1步,快指针移动2步,直到指针为空
    // 3. 若遍历过程中,慢指针和快指针相遇,则说明有环,否则说明没有环
    let p1 = head;
    let p2 = head.next;
    while(p1 && p2 && p1.next && p2.next) {
        if (p1 === p2) {
            return true;
        }
        p1 = p1.next;
        p2 = p2.next.next;
    }

    return false;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
上次更新: 3/2/2022, 10:27:51 AM