LeetCode 141简单链表 · 快慢指针
环形链表 图解题解
链表里是否藏着一个圈?快慢指针一追一赶,答案自然浮现。
判断链表有没有环,就像操场上快慢两个跑步者:慢的一步、快的两步,若是直道(无环)快的早早冲出终点遇到 null;若跑道是个圈,快的迟早从后面套圈追上慢的——两人相遇就证明有环。整个过程只需两个指针变量,不用额外空间记录谁走过哪里。
这道题到底在问什么
判断链表中是否存在环。
- head
- 3→2→0→-4,尾部连回 2
- 输出
- true
最优解:一步一步想明白
- 3哈希集合能判断是否再次访问同一节点,但快慢指针可以 O(1) 空间。
- 4进入环后,fast 每轮比 slow 多走一步,距离会不断缩小,最终相遇。
- 5slow=fast=3尾节点不是 null,而是回到值为 2 的节点。先让 slow 和 fast 都站在头节点 3。
- 6slow: 3 → 2慢指针每轮只走一步,先从 3 到 2。
- 7fast: 3 → 2 → 0快指针不是一步瞬移。它一轮走两跳:先到 2,再到 0。把两跳拆开看,快慢的速度差才显出来。
- 8fast: 0 → -4 → 2第二轮 slow 到 0;fast 从 0 到 -4,再沿回绕箭头回到 2。环开始被画面看见了。
- 9slow=-4,fast=-4进环后,fast 每轮比 slow 多追一格。距离一圈圈缩小,最后在 -4 相遇。
- 10return false如果没有环,fast 沿着 next 一直走,最终会先碰到 null。只有相遇,才说明有环。
- 11进环后 fast 每轮逼近 1 步 → 间距只减不增 → 必然相遇这才是真正的关键帧:相遇。为什么快慢指针一定相遇、不会擦肩而过?进了环以后,fast 每一轮比 slow 多走一步,两者的间距每一轮恰好减一,只会变小、绝不会跳过。间距迟早减到零,它们一定踩在同一个节点上。相遇,就证明有环。
- 14相遇代表有环;fast 到 null 代表无环。
- 17compare pointer两个节点值都为 1,但不是同一个节点。不能用 val 比较。
- 22这题学完不要乱跳,下一步去 对应专题 连刷同类题;卡住时用 AI 答疑追问“为什么这一步成立”,比只背答案更稳。
⚠️ 容易写错的地方
✗ 错:比较节点值是否相等
✓ 对:比较节点引用是否相同
不同节点可能有相同值。
✗ 错:while 里不判 fast.next
✓ 对:先保证 fast 和 fast.next 存在
fast 要走两步。
✗ 错:相遇前先移动顺序混乱
✓ 对:每轮先移动,再判断相遇
初始化时 slow==fast,不能直接判 true。
完整代码(Python / C++ / Java)
Python
class Solution:
def hasCycle(self, head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow is fast:
return True
return FalseC++
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}
};Java
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) return true;
}
return false;
}
}套路模板 · 挖空骨架
# 快慢指针:同一起点,慢走一步、快走两步
slow = fast = head
while ____ and ____: # fast 和 fast.next 都不为空
slow = slow.next # 慢指针走一步
fast = fast.next.next # 快指针走两步
if ____: # slow 和 fast 相遇
return True
return False # fast 先到 null = 无环ListNode *slow = head, *fast = head;
while (____ && ____) { // fast && fast->next 都不为空
slow = slow->next; // 慢走一步
fast = fast->next->next; // 快走两步
if (____) return true; // slow == fast 相遇
}
return false; // fast 到 null = 无环ListNode slow = head, fast = head;
while (____ != null && ____ != null) { // fast、fast.next 非空
slow = slow.next; // 慢走一步
fast = fast.next.next; // 快走两步
if (____) return true; // slow == fast 相遇
}
return false; // fast 到 null = 无环复杂度
时间复杂度
O(n)
无环走到尾,有环在环内相遇
空间复杂度
O(1)
只用 slow/fast 两个指针
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 环形链表 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
如何找到环的入口?+
LC142:相遇后让一个指针回到头,两指针同速各走一步,再次相遇的节点就是环入口。
为什么快慢指针一定会相遇?+
进环后 fast 每轮相对 slow 逼近 1 步,环长有限,间距必然减到 0。
哈希法和快慢指针怎么选?+
哈希法更直观但要 O(n) 空间;快慢指针只要 O(1) 空间,是面试更想看的答案。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。