LeetCode 141. 环形链表
题目描述
思路分析
解法一:快慢指针(Floyd 判环)(推荐)
核心思路:
- slow 每次走 1 步,fast 每次走 2 步,同时从 head 出发。
- 如果存在环,fast 会在环内追上 slow;如果无环,fast 会先走到 nil。
- 题目只需判断是否相遇,不需要定位入口。
复杂度分析:
- 时间复杂度:O(n),其中 n 表示链表节点数。
- 空间复杂度:O(1),仅使用常数个指针变量。
class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
// 快慢指针从头结点出发
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
// 若相遇说明存在环
if (slow == fast) {
return true;
}
}
return false;
}
}
func hasCycle(head *ListNode) bool {
if head == nil || head.Next == nil {
return false
}
// 快慢指针从头结点出发
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
// 若相遇说明存在环
if slow == fast {
return true
}
}
return false
}
解法二:哈希集合
核心思路:
- 遍历链表时将节点指针加入集合。
- 若遇到已存在的节点,说明出现重复访问,即存在环。
复杂度分析:
- 时间复杂度:O(n),其中 n 表示链表节点数。
- 空间复杂度:O(n),其中 n 表示哈希集合存储的节点数。
class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> visited = new HashSet<>();
ListNode current = head;
while (current != null) {
// 已访问过则存在环
if (visited.contains(current)) {
return true;
}
visited.add(current);
current = current.next;
}
return false;
}
}
func hasCycle(head *ListNode) bool {
visited := make(map[*ListNode]struct{})
current := head
for current != nil {
// 已访问过则存在环
if _, ok := visited[current]; ok {
return true
}
visited[current] = struct{}{}
current = current.Next
}
return false
}
相似题目
| 题目 | 难度 | 考察点 |
|---|---|---|
| 142. 环形链表 II | 中等 | Floyd 判环 |
| 287. 寻找重复数 | 中等 | 快慢指针 |
| 202. 快乐数 | 简单 | 快慢指针、哈希表 |
| 876. 链表的中间结点 | 简单 | 快慢指针 |
| 160. 相交链表 | 简单 | 双指针 |
| 234. 回文链表 | 简单 | 快慢指针 |
本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0
许可协议,转载请注明出处!