# 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
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
复杂度分析:
- 时间复杂度:
O(n)
- 空间复杂度:
O(1)