题目描述
思路解析动画文字版
记住这三步:找中点 → 反转后半 → 交替合并。下面逐帧看清每一步指针怎么动。
① 快慢找中点 · 起步:找中点用快慢指针:slow 一次走 1 格、fast 一次走 2 格,都从头出发。fast 到尽头时,slow 正好停在中点。
① 第 1 轮 · slow 走 1 格:第 1 轮:slow 先稳稳走 1 格到下标 1。接着看 fast 跨两格——拆两小跳看清楚。
① 第 1 轮 · fast 第 1 跳:fast 的第一小跳:跨到下标 1。
① 第 1 轮 · fast 第 2 跳:fast 的第二小跳:再跨到下标 2。slow 走 1、fast 走 2 的 2 倍速,让 fast 到头时 slow 恰好在中点。
① 第 2 轮 · slow 走 1 格:第 2 轮:slow 先稳稳走 1 格到下标 2。接着看 fast 跨两格——拆两小跳看清楚。
① 第 2 轮 · fast 第 1 跳:fast 的第一小跳:跨到下标 3。
① 第 2 轮 · fast 第 2 跳:fast 的第二小跳:再跨到下标 4。slow 走 1、fast 走 2 的 2 倍速,让 fast 到头时 slow 恰好在中点。
① 第 3 轮 · 收尾跳:fast 走到链表最后一个节点(下标 5),无法再跨两格,找中点结束。此刻 slow 停在下标 3,正是正中间。
① 劈分两半:劈分完成:前半是下标 0…2(绿色,共 3 个),后半是下标 3…5(共 3 个)。slow 指向后半的第一个,下一步把后半整段反转。
② 反转后半 · 断开:先把前半和后半断开:前半最后一个(下标 2)的 next 置空(中间那根连线变 ·)。cur 从后半头 下标 3 起步,prev 初始为空。
② 反转 · 第 1 步 · 存后继:掉头前先存好后继:nxt = cur.next = 下标 4。不先存,掉头后就找不到下一个了(链表题最常见的丢 next 坑)。
② 反转 · 第 2 步 · 存后继:掉头前先存好后继:nxt = cur.next = 下标 5。不先存,掉头后就找不到下一个了(链表题最常见的丢 next 坑)。
② 反转 · 第 2 步 · 掉头:把 cur(下标 4) 的箭头掉头指向 prev(下标 3):那根连线变 ←。后半段被一节一节翻过来。
② 反转 · 第 3 步 · 存后继:cur 在下标 5,它是后半最后一个,nxt 为空。
② 反转 · 第 3 步 · 掉头:把 cur(下标 5) 的箭头掉头指向 prev(下标 4):那根连线变 ←。后半段被一节一节翻过来。
② 反转完成:后半反转完成:head2 落在下标 5(原来的最后一个 6),它是反转后半的新头。现在前半 1→2→3、反转后半 6→5→4,准备交替合并。
③ 交替合并 · 起始:把链表摆成两行:上「前半 1→2→3」、中「反转后半 6→5→4」,下面是空的结果行。head1 指前半头、head2 指后半头,从前半先取。
③ 第 1 节 · 取前半:轮到取前半:head1 指向 1(下标 0),把它接到结果尾。
③ 第 1 节 · 接入 1:把 1 接到结果尾(变绿),前半取走的节点标灰、指针前移。下一节轮到取后半。
③ 第 2 节 · 取后半:轮到取后半:head2 指向 6(下标 0),把它接到结果尾。前后交替是重排的关键。
③ 第 2 节 · 接入 6:把 6 接到结果尾(变绿),后半取走的节点标灰、指针前移。下一节轮到取前半。
③ 第 3 节 · 取前半:轮到取前半:head1 指向 2(下标 1),把它接到结果尾。
③ 第 3 节 · 接入 2:把 2 接到结果尾(变绿),前半取走的节点标灰、指针前移。下一节轮到取后半。
③ 第 4 节 · 取后半:轮到取后半:head2 指向 5(下标 1),把它接到结果尾。前后交替是重排的关键。
③ 第 4 节 · 接入 5:把 5 接到结果尾(变绿),后半取走的节点标灰、指针前移。下一节轮到取前半。
③ 第 5 节 · 取前半:轮到取前半:head1 指向 3(下标 2),把它接到结果尾。
③ 第 5 节 · 接入 3:把 3 接到结果尾(变绿),前半取走的节点标灰、指针前移。下一节轮到取后半。
③ 第 6 节 · 取后半:轮到取后半:head2 指向 4(下标 2),把它接到结果尾。前后交替是重排的关键。
③ 第 6 节 · 接入 4:把 4 接到结果尾(变绿),后半取走的节点标灰、指针前移。两半都取完,重排结束。
③ 核对 · 第 1 位:两半接完,结果 1→6→2→5→3→4。回头核一遍:第 1 位 1 来自前半头。
③ 核对 · 第 2 位:第 2 位 6 来自后半(从尾往回),前后交替无误。
③ 核对 · 第 3 位:第 3 位 2 来自前半,前后交替无误。
③ 核对 · 第 4 位:第 4 位 5 来自后半(从尾往回),前后交替无误。
③ 核对 · 第 5 位:第 5 位 3 来自前半,前后交替无误。
③ 核对 · 第 6 位:最后一位 4。整条 1→6→2→5→3→4 正是 L0→Ln→L1→Ln-1→… 的头尾交替,重排正确。
空 / 单节点 / 两节点 / 奇数长先想清。奇数时中点归前半,写法用 fast.next && fast.next.next 天然处理。
三个高频追问:中点条件的选择、栈解法的空间代价、合并终止条件。
参考代码
def reorderList(head): if not head or not head.next: return # ① 快慢找中点 slow = fast = head while fast.next and fast.next.next: slow = slow.next fast = fast.next.next # ② 反转后半(从 slow.next 起) second = slow.next slow.next = None # 断开前后两半 prev = None while second: nxt = second.next second.next = prev prev = second second = nxt # ③ 前后交替合并 first, second = head, prev while second: n1, n2 = first.next, second.next first.next = second second.next = n1 first, second = n1, n2复杂度
- 时间:O(n),找中点走半条 + 反转半条 + 合并半条,都是线性
- 空间:O(1),原地反转后半 + 原地接线,只用常数个指针,不新建节点
易错点
面试追问把动画讲成自己的话
追问为什么用 fast.next && fast.next.next 而不是 fast && fast.next?
追问能不能不反转、用栈做?
追问合并循环用 while(second) 还是 while(first)?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
删除倒数第 N 个结点
LeetCode 19 · 中等 · 沿着 链表 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题