快慢指针能检测环是因为在有环时快指针(每次两步)必在环内追上慢指针(每次一步),本质是相对速度为1的追及问题;无环时快指针先达nullptr;空间复杂度O(1),且需严格判空避免崩溃。

为什么快慢指针能检测环
因为如果链表有环,快指针(每次走两步)迟早会追上慢指针(每次走一步)——这本质上是「相对运动」问题:在环内,快指针以每轮一步的速度逼近慢指针。没环时,快指针会先走到 nullptr;有环时,二者必然在环内某节点相遇。
注意:不能只靠判断是否重复访问某个地址来检测,C++ 没有内置哈希地址集合,手动维护 std::unordered_set<ListNode*> 虽可行但空间复杂度 O(n),而快慢指针是 O(1)。
标准快慢指针实现要检查空指针
常见错误是忘记判空,导致访问 nullptr->next 崩溃。必须在每次读取 fast->next 或 fast->next->next 前确认非空。
- 初始化时检查
head和head->next是否为空 - 循环中每次移动前检查
fast != nullptr && fast->next != nullptr - 推荐写法:
while (fast != nullptr && fast->next != nullptr) {而不是先移动再判断
如何定位环的入口节点
检测到环后,若还需返回环起点(比如 LeetCode 142),方法是:让一个指针从头出发,另一个从相遇点出发,都每次走一步,再次相遇处即为环入口。
立即学习“C++免费学习笔记(深入)”;
原理是数学推导出的路径关系:设头到入口距离为 a,入口到相遇点距离为 b,环长为 c,则满足 2(a + b) = a + b + n*c → a = n*c - b,所以同步走 a 步后必在入口相遇。
- 必须先确认有环,否则第二阶段无意义
- 两个指针都用
slow类型(一次走一步),别再用快指针 - 比较的是节点地址(
==),不是值(->val)
边界情况容易漏掉
单节点无环(head->next == nullptr)、空链表、环长度为 1(自环)这些都会让快指针很快暴露问题。
- 空链表直接返回 false
- 单节点链表:
fast->next为nullptr,循环不进入,正确返回 false - 自环(
head->next == head):第一轮就相遇,没问题 - 最险情况是环在最后一个节点指向自己,快指针仍会在第二轮迭代中捕获
真正容易出错的是把 fast = fast->next->next 写在判空检查之前——这种 bug 在本地小数据测不出,一到在线评测就 SIGSEGV。


















