23. 合并 K 个升序链表
困难
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6示例 2:
输入:lists = [] 输出:[]示例 3:
输入:lists = [[]] 输出:[]提示:
k == lists.length0 <= k <= 10^40 <= lists[i].length <= 500-10^4 <= lists[i][j] <= 10^4lists[i]按升序排列lists[i].length的总和不超过10^4
📝 核心笔记:合并 K 个升序链表 (Merge K Sorted Lists)
1. 核心思想 (一句话总结)
“锦标赛赛制:两两对决,胜者晋级,直到决出总冠军。”
这本质上就是归并排序 (Merge Sort)的逻辑,只不过这里的“元素”变成了“一条链表”。
- 我们不按顺序一个一个合,而是将 k 条链表从中间切开,左边一半自己去合,右边一半自己去合。
- 最终问题回归到我们最熟悉的合并两个有序链表 (LC 21)。
2. 算法流程 (递归分治)
- 分解 (Divide):
- 将当前的链表数组范围
[i, j)对半切分。 - 递归处理左区间
[i, mid)。 - 递归处理右区间
[mid, j)。
- 将当前的链表数组范围
- 终止 (Base Case):
- 如果范围内没有链表 (
m == 0):返回null。 - 如果范围内只有一条链表 (
m == 1):不用合了,直接返回这条链表。
- 如果范围内没有链表 (
- 合并 (Conquer):
- 获取左边合并好的大链表
left。 - 获取右边合并好的大链表
right。 - 调用
mergeTwoLists(left, right)将它们合二为一。
- 获取左边合并好的大链表
🔍 代码回忆清单
// 题目:LC 23. Merge k Sorted Lists class Solution { public ListNode mergeKLists(ListNode[] lists) { // 范围是左闭右开 [0, length) return mergeKLists(lists, 0, lists.length); } // 分治核心函数 private ListNode mergeKLists(ListNode[] lists, int i, int j) { int m = j - i; // 当前范围内的链表数量 // 1. Base Case: 没链表了 if (m == 0) return null; // 2. Base Case: 只剩一条,直接交上去 if (m == 1) return lists[i]; // 3. 分治:计算中点 // i + m / 2 等同于 (i + j) / 2 ListNode left = mergeKLists(lists, i, i + m / 2); ListNode right = mergeKLists(lists, i + m / 2, j); // 4. 合并:复用 LC 21 的逻辑 return mergeTwoLists(left, right); } // 复用合并两个有序链表的代码 (略) private ListNode mergeTwoLists(ListNode list1, ListNode list2) { ... } }🖼️ 数字演练
输入:[L1, L2, L3, L4](4条链表)
- Level 1 (Top): Range
[0, 4). Split into[0, 2)and[2, 4). - Level 2 (Left): Range
[0, 2). Split into[0, 1)and[1, 2).
- Return
L1andL2. - Merge:
New_L12 = merge(L1, L2).
- Return
- Level 2 (Right): Range
[2, 4). Split into[2, 3)and[3, 4).
- Return
L3andL4. - Merge:
New_L34 = merge(L3, L4).
- Return
- Back to Level 1:
- Merge:
Final = merge(New_L12, New_L34).
- Merge: