
本题是链表环检测的经典问题,主要包含哈希表解法与快慢指针最优解。
1. 简单解法:哈希表(Set 容器)
核心思路是利用哈希表的唯一性记录遍历过的节点:
- 遍历链表时,将每个节点的地址插入 C++ STL 的
set<ListNode*>容器; - 若当前节点已存在于
set中,说明该节点就是环的第一个节点; - 若遍历到链表末尾仍无重复节点,则链表无环。
该方法逻辑简单易懂,此处不再展开赘述,接下来重点讲解更优的快慢指针解法。
2. 最优解法:快慢指针(空间复杂度 O(1))
第一步:判断链表是否有环
利用'一快一慢'两个指针遍历链表,通过是否相遇判断是否存在环:
- 快指针(fast):每次走 2 步;
- 慢指针(low):每次走 1 步;
- 若链表无环:fast 指针会先走到链表末尾(
fast == nullptr或fast->next == nullptr),两个指针永远不会相遇; - 若链表有环:fast 指针会在环内'追上'low 指针,最终两者必定相遇(因为 fast 每次比 low 多走 1 步,相当于每次向 low 靠近 1 步)。


第二步:找到环的第一个节点
当确认链表有环后,我们需要进一步定位环的入口,先定义几个关键长度:
a:链表头结点到环入口的距离;b:环入口到快慢指针相遇点的距离;c:相遇点回到环入口的距离。

推导:
- 慢指针(low)走到相遇点时,总路程为:
a + b; - 快指针(fast)走到相遇点时,总路程为:
a + b + n×(b + c)(n为 fast 绕环的圈数); - 由于 fast 速度是 low 的 2 倍,因此路程也为 2 倍:
2×(a + b) = a + b + n×(b + c);


