Q142 环形链表II
目录
题目:给定一个链表的头节点
head,返回链表开始入环的第一个节点。如果链表无环,返回null。
1 我的想法
最容易踩的坑:以为快慢指针第一次相遇就是答案。第一次相遇点不是环入口——相遇后还要从头再走一遍:让 cur(从 head 出发)和 fast(停在相遇点)同步各走 1 步,两者相遇的位置才是环入口。
2 简要回答
- fast 每次 2 步、slow 每次 1 步,若
fast或fast->next为空 → 无环,返回 null。 - 第一次
fast == slow→ 有环,记下相遇点。 cur = head,cur与fast各走 1 步,直到fast == cur→ 返回该节点(环入口)。
- 时间复杂度:$O(n)$
- 空间复杂度:$O(1)$
3 为什么第一次相遇点不是入口
第一次相遇发生在环内,具体是环内哪个点取决于 a 和 b 的比例,没有任何规律保证它是入口。所以第二阶段必须有。
4 为什么第二轮双指针能在入口相遇
设 head→环入口距离为 a,环入口→第一次相遇点(沿前进方向)距离为 b,环长为 c。
相遇时(fast 走的路程是 slow 的 2 倍):
| |
含义:
- 从 head 走
a步 → 到达环入口; - 从相遇点走
a步 → 绕n圈后再退b步 → 也到达环入口。
所以 cur(head 出发)和 fast(相遇点出发)同步各走 1 步,恰好都在走 a 步后到达环入口,相遇。
5 代码
| |
用 1→2→3→4→5→(3)(3 是环入口,环长 3)验证:第一次相遇点在 5,第二阶段从 head 和 5 同步走,在 3 相遇 → 返回 3 ✓。
6 无环与空指针
- 无环:
fast先到末尾,fast == nullptr退出循环,返回 null。 - 空链表 / 单节点:
fast == nullptr或fast->next == nullptr,返回 null。 fast->next->next在fast->next == nullptr已排除的前提下是安全的(最多为 null,下一轮循环判断)。
7 易错点
- 第一次
fast == slow直接 return 是错的:那只是环内某个点,不是入口。 - 第二阶段不需要判空:已确认有环,
cur和fast必然相遇。 - 无环判断必须覆盖
fast == nullptr和fast->next == nullptr两种。 - 第一阶段别把 slow 写成走 2 步——快慢都走 2 步永远追不上。