2025/12/26 9:28:33
网站建设
项目流程
建网站中企动力最行,网站关键字怎么修改,代理记账 营销型网站,网站域名的用处目录
一、876. 链表的中间节点#xff08;快慢指针基础#xff09;
题目核心
核心难点拆解
深度思路#xff08;盒子 - 标签 - 纸条模型#xff09;
代码实现#xff08;带关键点标注#xff09;
易踩坑点 底层原理
二、141. 环形链表#xff08;判环的必然…目录一、876. 链表的中间节点快慢指针基础题目核心核心难点拆解深度思路盒子 - 标签 - 纸条模型代码实现带关键点标注易踩坑点 底层原理二、141. 环形链表判环的必然性题目核心核心难点拆解深度思路盒子 - 标签 - 纸条模型代码实现带关键点标注易踩坑点 底层原理三、142. 环形链表 II环入口的数学推导题目核心核心难点拆解深度思路盒子 - 标签 - 纸条模型代码实现带关键点标注易踩坑点 底层原理四、143. 重排链表快慢指针 反转 合并的组合题目核心核心难点拆解深度思路盒子 - 标签 - 纸条模型代码实现带关键点标注易踩坑点 底层原理五、跨题深度对比快慢指针的应用边界快慢指针的通用应用场景进阶思考这四道题是快慢指针在链表中的经典应用从基础定位中间节点到环检测是否有环、环入口再到组合操作重排链表核心逻辑均围绕 “标签指针的速度差” 展开。本次聚焦底层原理、必踩坑点、代码关键细节用「盒子节点、标签指针、纸条next」模型分析 “为什么这么设计”。一、876. 链表的中间节点快慢指针基础题目核心给定非空链表返回中间节点若有两个中间节点返回第二个如1→2→3→4→5返回 31→2→3→4返回 3。核心难点拆解为什么快指针走 2 步、慢指针走 1 步快慢指针的速度比为 2:1当快指针到达链表末尾时慢指针恰好走了链表长度的一半 —— 这是 “定位中间” 的核心逻辑本质是利用速度差实现 “一次遍历定位中间”避免先统计长度再遍历的 O (2n) 操作。偶数长度时为什么 slow 停在第二个中间节点以1→2→3→4为例fast 初始在 1依次走 2→4→nullslow 初始在 1依次走 2→3当 fast 走到 null 时slow 恰好停在第二个中间节点3符合题目要求。奇数长度时slow刚好停在正中间的节点。深度思路盒子 - 标签 - 纸条模型模型元素角色与逻辑盒子链表节点实体如 1、2、3、4顺序固定标签-slow从 head 出发每次移动 1 个盒子的标签-fast从 head 出发每次移动 2 个盒子的标签纸条标签的移动依赖盒子的next纸条即slow slow.next无修改操作仅定位代码实现带关键点标注class Solution { public ListNode middleNode(ListNode head) { // 关键点1快慢标签均从head盒子出发 ListNode slow head; ListNode fast head; // 关键点2循环条件双层防御——避免fast或fast.next为null时的空指针 // 若写“fast ! null”当fast在最后一个盒子时fast.next为null执行fast.next.next会报错 while (fast ! null fast.next ! null) { slow slow.next; // slow标签移动1个盒子 fast fast.next.next; // fast标签移动2个盒子 } // 关键点3fast到末尾时slow恰好停在中间盒子 return slow; } }易踩坑点 底层原理坑 1循环条件仅写fast ! null→ 当链表长度为偶数时fast.next为 null执行fast.next.next会空指针坑 2快慢指针初始位置不一致如 slow 从 headfast 从 head.next→ 会导致中间节点定位偏移原理快慢指针的速度比决定了 “相对位移”2:1 的速度比是定位中间节点的唯一最优解其他比例无法精准定位。二、141. 环形链表判环的必然性题目核心判断链表是否存在环即某个节点的next指向之前的节点形成循环。核心难点拆解为什么有环的话快慢指针一定会相遇若链表有环快慢指针进入环后会持续绕圈slow 速度 1fast 速度 2相对速度为 1fast 每次比 slow 多走 1 个节点相当于 slow 静止fast 以速度 1 向 slow 靠近因此必然会追上不会永远追不上。为什么 fast 不能走 3 步 / 4 步若 fast 速度为 3相对速度为 2可能会 “跳过” slow如环长为 2 时fast 和 slow 的位置差始终为奇数无法相遇——2 步是唯一能保证相遇的速度。深度思路盒子 - 标签 - 纸条模型模型元素角色与逻辑盒子链表节点实体若有环则存在 “循环盒子区间”标签-slow每次移动 1 个盒子的标签-fast每次移动 2 个盒子的标签纸条标签移动依赖next纸条环的本质是 “某个盒子的纸条指向之前的盒子”代码实现带关键点标注public class Solution { public boolean hasCycle(ListNode head) { // 关键点1空链表/单节点链表无环直接返回 if (head null || head.next null) return false; // 关键点2快慢标签初始位置错开避免初始状态slowfast ListNode slow head; ListNode fast head.next; // 关键点3若fast追上slow则有环若fast到末尾则无环 while (slow ! fast) { // 无环的终止条件fast或fast.next为null if (fast null || fast.next null) return false; slow slow.next; fast fast.next.next; } // 退出循环说明slowfast有环 return true; } }易踩坑点 底层原理坑 1快慢标签初始位置相同均为 head→ 循环条件slow ! fast会直接跳过初始检查误判无环坑 2循环条件写fast ! null→ 当 fast 在环内时永远不会为 null导致死循环原理相对速度为 1是快慢指针相遇的核心前提速度差过大可能导致 “追及失败”。三、142. 环形链表 II环入口的数学推导题目核心若链表有环返回环的入口节点若无环返回 null如3→2→0→-4→2环入口是 2。核心难点拆解环入口的数学推导最核心定义a头节点到环入口的盒子数b环入口到快慢指针相遇点的盒子数c相遇点到环入口的盒子数环长L b c。快慢指针的路程关系slow 走了a b到相遇点fast 走了a b nL绕了 n 圈后相遇因 fast 速度是 slow 的 2 倍故2(a b) a b nL→ 化简得a c (n-1)L。结论头节点到环入口的距离 相遇点到环入口的距离 (n-1) 圈环长→ 因此让一个标签从头节点出发一个从相遇点出发同速移动会在环入口相遇。深度思路盒子 - 标签 - 纸条模型模型元素角色与逻辑盒子包含 “头→入口” 的直线盒子、“入口→相遇点→入口” 的环形盒子标签-slow/fast先找相遇点-ptr1/ptr2分别从头节点、相遇点出发同速找入口纸条标签移动依赖next纸条环入口的纸条是 “直线盒子” 与 “环形盒子” 的连接点代码实现带关键点标注public class Solution { public ListNode detectCycle(ListNode head) { // 步骤1找快慢指针的相遇点 ListNode slow head; ListNode fast head; boolean hasCycle false; while (fast ! null fast.next ! null) { slow slow.next; fast fast.next.next; if (slow fast) { // 找到相遇点 hasCycle true; break; } } // 无环直接返回 if (!hasCycle) return null; // 步骤2找环入口——核心逻辑 ListNode ptr1 head; // 从头节点出发的标签 ListNode ptr2 slow; // 从相遇点出发的标签 while (ptr1 ! ptr2) { ptr1 ptr1.next; // 同速移动每次1个盒子 ptr2 ptr2.next; } // 相遇时即为环入口 return ptr1; } }易踩坑点 底层原理坑 1推导时忽略nL绕圈次数→ 误以为a c但实际 n≥1 时仍成立绕圈不影响最终相遇坑 2找相遇点后直接返回 slow → 相遇点不是环入口需二次移动原理a c (n-1)L是环入口的数学本质同速移动的标签会在 “环入口” 抵消绕圈的影响。四、143. 重排链表快慢指针 反转 合并的组合题目核心将链表L0→L1→…→Ln-1→Ln重排为L0→Ln→L1→Ln-1→…如1→2→3→4→1→4→2→3。核心难点拆解为什么拆分为 “找中间 反转后半段 合并”重排的本质是 “前半段与反转后的后半段交替拼接”因此需要找中间将链表拆分为L0→L1和L2→L3偶数长度反转后半段将L2→L3转为L3→L2合并L0→L3→L1→L2。拆分后必须断开链表的原因若不断开前半段与后半段的连接如1→2→3→4不把 2 的 next 设为 null反转后半段后会形成环3 的 next 指向 2导致合并时死循环。深度思路盒子 - 标签 - 纸条模型模型元素角色与逻辑盒子拆分为前半段盒子、后半段盒子反转后半段盒子的纸条方向标签-slow/fast找中间节点-prev/cur反转后半段-p1/p2合并两个链表纸条操作包括 “断开前半段末尾的纸条”“反转后半段的纸条方向”“交替连接两个链表的纸条”代码实现带关键点标注class Solution { public void reorderList(ListNode head) { // 边界防御空链表/单节点无需处理 if (head null || head.next null) return; // 步骤1找中间节点拆分链表 ListNode slow head; ListNode fast head; while (fast.next ! null fast.next.next ! null) { slow slow.next; fast fast.next.next; } ListNode mid slow.next; // 后半段头盒子 slow.next null; // 关键点1断开前半段与后半段避免环 // 步骤2反转后半段 ListNode reversedMid reverse(mid); // 步骤3合并前半段与反转后的后半段 merge(head, reversedMid); } // 反转链表辅助方法 private ListNode reverse(ListNode head) { ListNode prev null; ListNode cur head; while (cur ! null) { ListNode temp cur.next; cur.next prev; // 反转纸条方向 prev cur; cur temp; } return prev; } // 交替合并两个链表辅助方法 private void merge(ListNode p1, ListNode p2) { while (p1 ! null p2 ! null) { ListNode temp1 p1.next; // 暂存前半段下一个盒子 ListNode temp2 p2.next; // 暂存后半段下一个盒子 p1.next p2; // 前半段盒子连接后半段盒子 p2.next temp1; // 后半段盒子连接前半段下一个盒子 p1 temp1; // 移动标签 p2 temp2; } } }易踩坑点 底层原理坑 1拆分链表时未断开slow.next→ 反转后半段后形成环合并时死循环坑 2合并时未暂存next→ 直接修改p1.next会丢失原链表的后续盒子原理重排是 “基础操作的组合”快慢指针定位中间是前提反转是核心合并是收尾三者缺一不可。五、跨题深度对比快慢指针的应用边界题目编号核心场景快慢指针作用核心原理876找中间节点利用速度差定位中间2:1 速度比的位移特性141判断是否有环利用相对速度 1 实现追及环内的相对位移必然相遇142找环入口先追及再同速移动利用路程公式抵消绕圈a c (n-1)L的数学推导143重排链表定位中间节点拆分链表2:1 速度比的中间定位特性快慢指针的通用应用场景定位类找中间节点、找倒数第 k 个节点快指针先移 k 步环操作类判断环、找环入口组合操作类作为拆分链表的前置步骤如重排链表。进阶思考若链表是双向链表判环 / 找入口的方法会简化吗→ 可以直接记录访问过的节点无需快慢指针但空间复杂度从 O (1) 变为 O (n)重排链表的时间复杂度是多少→ 找中间 O (n) 反转 O (n) 合并 O (n)总时间 O (n)空间 O (1)原地操作。