题目描述
思路解析动画文字版
把全部节点倒进数组排一遍能做,但完全没利用「每条本来就有序」这个大便宜——重排是 O(N log N),还白白丢掉了有序信息。
转折:把 K 条捉对合并——合并两条有序链表我们是会的(比头节点,谁小接谁)。两两合完再两两合,像淘汰赛,log k 轮就汇成一条。每个节点每轮只被碰一次,所以是 O(N log k),比重排更快。
合并 A、B · 起步:先合并 A、B。p1 指 A 头 1,p2 指 B 头 1,结果链表(下方)还空着(虚线占位)。挂个 dummy 哨兵当结果起点,开始比头。
1(A) ≤ 1(B) · 取 A 的 1:两个头都是 1,1 ≤ 1 取 A 的 1(一样大先接谁都行)接进结果,p1 前进到 4。结果链表长出第一个 1,tail 指向它。
4(A) > 1(B) · 取 B 的 1:现在比 A 的 4 和 B 的 1:4 大于 1,取 B 的 1,p2 前进到 3。结果:1 → 1。
4(A) > 3(B) · 取 B 的 3:A 的 4 仍比 B 的 3 大:4 大于 3,取 B 的 3,p2 前进到 4。结果:1 → 1 → 3。谁小接谁,指针各自往后爬。
4(A) ≤ 4(B) · 取 A 的 4:这回 A、B 头都是 4:4 ≤ 4 取 A 的 4,p1 前进到 5。结果:1 → 1 → 3 → 4。
5(A) > 4(B) · 取 B 的 4 · B 用完:比 A 的 5 和 B 的 4:5 大于 4,取 B 的 4,p2 走到头——B 用完了。结果:1 → 1 → 3 → 4 → 4。
负例 · B 空了 · A 剩段整条接上:关键负例:一条先走空(B 空),就不必再逐个比了——把另一条剩下的整段(A 的 5)直接接到结果尾巴。结果:1 → 1 → 3 → 4 → 4 → 5。
A+B 合并完成 · 再与 C 合:A、B 合成了 1→1→3→4→4→5。这就是「合并两条」的一整轮。下一轮拿这个结果再和 C=[2→6] 合并,还是同一套:比头、接小的,最终汇成 1→1→2→3→4→4→5→6。
面对「合并 K 个」别慌:把它拆成你已经会的「合并两个」,再用分治两两推进。或者用小顶堆同时盯住 K 个头,每次弹最小,也是 O(N log k)。
迁移阶梯:把这题练到能复述后,再去同类题里迁移:先复用状态定义,再调整边界条件。
边界三连:边界三连:极端输入先过一遍。
几个高频追问,记住答法。
参考代码
class Solution: def mergeKLists(self, lists): if not lists: return None if len(lists) == 1: return lists[0] mid = len(lists) // 2 left = self.mergeKLists(lists[:mid]) # 左半递归合成一条 right = self.mergeKLists(lists[mid:]) # 右半递归合成一条 return self.mergeTwo(left, right) # 再合并这两条 def mergeTwo(self, a, b): # 合并两条有序链(LC21) dummy = cur = ListNode(0) while a and b: if a.val <= b.val: cur.next, a = a, a.next else: cur.next, b = b, b.next cur = cur.next cur.next = a or b # 残段整条接上 return dummy.next复杂度
- 时间复杂度:O(N log k),N 个节点,每轮全碰一次、共 log k 轮
- 空间复杂度:O(log k),分治递归栈深度 log k(合并本身原地接指针)
可套用的代码模板
堆解法:把 K 个头扔进小顶堆,每次弹最小、接走,再把它的后继补进堆。堆顶永远是当前全局最小,同样 O(N log k)。
import heapqclass Solution: def mergeKLists(self, lists): h = [(node.val, i, node) for i, node in enumerate(lists) if node] heapq.heapify(h) # K 个头进堆 dummy = cur = ListNode(0) while h: val, i, node = heapq.heappop(h) # 弹出全局最小头 cur.next = node; cur = node if node.next: heapq.heappush(h, (node.next.val, i, node.next)) return dummy.next易错点
面试追问把动画讲成自己的话
追问为什么堆大小是 K 不是 N?
追问分治和堆怎么选?
追问一条条顺序合并为什么慢?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
K 个一组翻转链表
LeetCode 25 · 困难 · 沿着 链表 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题