LeetCode-快慢指针(链表)
🧠 核心场景:链表中的位置定位、测距与判环
判断用哪个模板的唯一标准:
是否涉及“相对位置变化 / 追及” → 倍速循环
是否涉及“倒数 / 固定间距” → 定距循环
⭐ 模板
模板一:倍速循环 (Double Speed)
核心逻辑:只有跑得快,才能根据“相对位置”算中点,或者在环里“套圈”。口诀:快走两步,慢走一步,这就叫倍速。
ListNode slow = head;
ListNode fast = head;// 必须保证 fast 能走两步,否则会空指针
while (fast != null && fast.next != null) {
slow = slow.next; // 慢走 1
fast = fast.next.next; // 快走 2// 【插入点】:如果有“追击/判圈”逻辑,写在这里
}
// 【结束点】:奇数长度 slow 在正中;偶数长度 slow 在右中点(第二个中点)👇 变型点拨 (只需改哪里):
找中点 (876):不用改,循环结束后直接 return slow。
判圈 (141):在【插入点】加一句 if (slow == fast) return true;。
找圈入口 (142):判圈相遇后,把一个指针扔回 head,改为同速(都走 1 步),再次相遇处即入口。
回文 (234):先用这套模板拿到 slow (中点),然后把 slow 后面的链表反转,再跟 头节点对比。
模板二:定距循环 (Fixed Gap)
核心逻辑:只要先拉开 N 步距离,当头走到终点,尾巴就在倒数第 N 个。口诀:快先走,慢后走,维持距离到尽头
// 必须用 Dummy,防止删除的是头节点
ListNode dummy = new ListNode(-1, head);
ListNode slow = dummy, fast = dummy;// 1. 制造间距:fast 先走 N+1 步 (为了删倒数第 N 个,slow 要在它前一个)
//⚠️ 默认题目保证 n 合法,若 n 可能非法,需在 for 中判断 fast == nullfor (int i = 0; i <= n; i++) {
fast = fast.next;
}// 2. 保持间距同速走:直到 fast 摸到 null
while (fast != null) {
fast = fast.next;
slow = slow.next;
}// 【操作点】:此时 slow 停在目标节点的前一位
- 返回答案
return dummy.next;
- 返回答案
👇 变型点拨 (只需改哪里):
删倒数第 N 个 (19):在【操作点】执行 slow.next = slow.next.next。
找倒数第 K 个 (面试题):slow、fast 都从 dummy 起步,fast 先走 K 步,循环结束时 slow 指向的就是倒数第 K 个节点, return slow 即为目标。
一句话总结记忆:找中点、找环 -> 用 while 同时起步,一快一慢。找倒数 -> 用 for 先跑几步,保持距离。
Notice:
- 倍速循环的“判空顺序” (防爆核心)在写 while 循环条件时,顺序绝对不能颠倒。
正确写法:while (fast != null && fast.next != null)
Java 会先判断左边,如果 fast 已经是 null,就不会去执行右边,从而避免报错
错误写法:while (fast.next != null && fast != null)
如果 fast 已经是 null,直接访问 fast.next 会立刻报 NullPointerException
记忆点:先判“人”在不在,再判“下一步”能不能走。
- 找中点的“偶数偏右”特性用标准倍速模板
(fast 走两步,slow 走一步) 找中点时,对于偶数长度的链表,slow 最终会停在 第二个 中间节点上。
链表:1 -> 2 -> 3 -> 4 标准模板结果:slow 指向 3。注意:有些题目(虽然少)要求找“左中点”(即 2),那时候循环条件要微调改为 fast.next != null && fast.next.next != null。
记忆点:默认模板是“偏右”的(LeetCode 876 标准答案)。
- 定距删除时的 “N” 还是 “N+1”?
场景:你要 删除 倒数第 N 个节点。必须做到:slow 指针必须停在 倒数第 N+1 个 节点(即目标节点的前驱),这样你才能执行 slow.next = slow.next.next。
操作:所以 fast 指针必须先走 N + 1 步(或者让 fast 指向 dummy,先走 N 步,效果一样
记忆点:要删除,必须多走一步,或者从 dummy 起步多算一个身位。
- 环的入口问题
快慢指针相遇时,起点到入口的距离,正好等于相遇点到入口的距离。
环形链表 II 的“回头位置”在 LeetCode 142 (找环入口) 中,当 slow 和 fast 第一次相遇后,开启“回马枪”阶段。新指针(或重置的 fast)必须回到 head (真正的头),而不是 dummy。
相关练习题
1. LeetCode 19. 删除链表的倒数第 N 个结点(测距流)
题意: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
2. LeetCode 876. 链表的中间结点(二倍速流)
题意: 给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
3. LeetCode 141. 环形链表(判圈流)
题意: 给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
4. LeetCode 142. 环形链表 II(判圈流)
题意: 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
5. LeetCode 234. 回文链表
题意: 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

