快慢指针法可靠:两指针从头出发,慢指针每步1,快指针每步2;若相遇则有环,若快指针先达nullptr则无环;其本质是相对运动下环内必追及,时间复杂度o(n),空间复杂度o(1)。

用快慢指针判断链表是否有环,核心就一句话:两个指针从头出发,一个每次走1步,一个每次走2步;如果它们能相遇,就有环;如果快指针先走到nullptr(或NULL),就没环。
为什么这个方法可靠
关键在于相对运动——快指针比慢指针每轮多走1步。一旦两个指针都进入环,快指针就会不断缩小与慢指针的距离,最终追上。哪怕环只有一个节点(自环),或者慢指针刚进环时快指针已在环里绕了几圈,只要存在环,就一定能在有限步内相遇。
无环时,快指针会比慢指针更早到达末尾,此时直接判定无环。
实际写代码要注意的细节
边界检查和指针安全是容易出错的地方:
- 开头先判断链表是否为空(
head == nullptr)或只有一个节点(head->next == nullptr),避免后续访问空指针 - 循环条件必须同时检查:
fast != nullptr && fast->next != nullptr——因为快指针要走两步,第二步前必须确保fast->next存在 - 不要在循环开始就比较
slow == fast,否则初始状态两者都在头节点,会误判为有环;应先移动再判断
典型代码结构(C++风格)
以下是最简练、可直接复用的逻辑框架:
bool hasCycle(ListNode* head) {
if (!head || !head->next) return false;
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}
这段代码时间复杂度是 O(n),空间复杂度是 O(1),不依赖额外容器,也不修改原链表结构。
它还能顺便帮你找到环入口和环长度
检测到环后,算法可以自然延伸:
- 找环入口:把慢指针移回头节点,快慢指针都改为每次走1步,再次相遇的位置就是环开始的地方
- 算环长度:从相遇点出发,固定一个指针,另一个继续走,数它绕一圈回到原点走了几步
这些扩展都不需要额外空间,全靠指针移动的数学关系推导而来。











