141. 环形链表(简单)

1,问题描述

141. 环形链表

难度:简单

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

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

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

示例 1:

img

1
2
3
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

img

1
2
3
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

img

1
2
3
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos-1 或者链表中的一个 有效索引

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

2,初步思考

​ 解法就是遍历然后,找出重复的节点

​ 解法1:空间缓存已经遍历过的节点,使用hashSet

​ 解法2:快慢指针,Floyd 判圈算法,快指针一次跑2步,慢指针一次跑1步

3,代码处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import support.ListNode;

import java.util.HashSet;
import java.util.Set;

public class _141环形链表 {

// 解法:官方快慢指针
public boolean hasCycle_slow_gov(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head, fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) return false;
slow = slow.next;
fast = fast.next.next;
}
return true;
}

// 解法:快慢指针
public boolean hasCycle_slow(ListNode head) {
boolean flag = false;
ListNode slow = head, fast = head.next;
while (fast != null && slow != null) {
if (flag) slow = slow.next;
fast = fast.next;
flag = !flag;
if (fast == slow) return true;
}
return false;
}

// 解法:空间换时间
public boolean hasCycle_area(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null) {
if (set.contains(head)) return true;
set.add(head);
head = head.next;
}
return false;
}
}

4,扩展知识

​ Floyd 判圈算法,又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一个可以在有限状态机、迭代函数或者链表中判断是否存在环,以及找出该环的起点和长度的算法。以下是对该算法的详细介绍:
算法原理
​ 该算法使用两个指针,一个慢指针(龟)和一个快指针(兔)。慢指针每次移动一步,快指针每次移动两步。如果存在环,快指针最终会追上慢指针。