快慢指针能检测环入口,是因为数学推导证明:设头到入口距离为a、入口到相遇点为b、环剩余为c,则2(a+b)=a+b+n(b+c)推出a=(n−1)(b+c)+c,故将slow重置至头、fast停在相遇点并同速前进,再次相遇处即环入口。

为什么快慢指针能检测环入口
单链表成环时,slow 和 fast 两个指针从头出发,fast 每次走两步、slow 每次走一步,若存在环,它们必在环内某点相遇。这不是巧合——设入环前有 a 个节点,环长为 b,相遇时 slow 走了 a + x 步(x 是环内距入口的偏移),fast 走了 a + x + nb(n 是绕环圈数)。由 2(a + x) = a + x + nb 可得 a = nb - x,即:从头节点和相遇点同时出发、每次走一步,二者必在环入口相遇。
如何用 C++ 实现标准检测逻辑
核心分两步:先判断是否有环,再定位入口。注意指针有效性检查必须到位,否则容易触发 nullptr->next 崩溃。
-
fast每次移动前都要检查fast != nullptr && fast->next != nullptr - 第一次相遇后,重置
slow到head,不再动fast,两者同步单步前进 - 循环条件是
slow != fast,退出时slow就是指向环入口的节点
ListNode* detectCycle(ListNode* head) {
ListNode *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) break;
}
if (!fast || !fast->next) return nullptr; // 无环
<pre class="brush:php;toolbar:false;">slow = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return slow;}
常见错误:为什么返回的不是环中任意节点而是入口
有人误以为第一次相遇点就是环入口,这是错的。该点只是环内某个位置,离入口可能差好几跳。真正入口由 a = nb - x 推出:从头走 a 步,等于从相遇点沿环走 nb - x 步(即退 x 步再绕 n-1 圈),最终落在入口。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 若只返回第一次相遇节点,
return slow在if (slow == fast)后直接写,会错 - 若忘记重置
slow,或重置后没同步移动,结果必然错误 - 链表为空或仅一个节点时,
fast->next访问会段错误,必须前置判空
边界场景与性能表现
这个算法时间复杂度是 O(n),空间复杂度 O(1),不依赖额外容器。但要注意几个真实易踩的坑:
- 输入为
nullptr时,第一轮while不进,直接返回nullptr,没问题 - 环长度为 1(自环)时,
fast第一步就走到slow->next == slow,仍满足推导,能正确返回该节点 - 若链表无环但极长,快慢指针仍会在
O(n)内结束,不会死循环 - 使用
std::shared_ptr或带析构逻辑的节点时,别在检测过程中意外释放节点,否则指针悬空
环入口检测真正难的不是算法本身,而是把「第一次相遇」和「第二次同步出发」这两个阶段的物理意义分清楚;很多人卡在第二步没重置 slow,或者重置后还继续用原来的 fast 绕圈。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










