683 字
3 分钟
合并 K 个升序链表
.jpg)
题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
解题思路
- 分治合并(最优):
- 将链表数组划分为两半
- 递归合并左右两半
- 合并结果链表
- 最小堆方法:
- 建立最小堆存储所有链表头节点
- 每次取堆顶节点加入结果链
- 更新堆顶为该节点下一节点
- 顺序合并(基础):
- 顺序合并相邻链表
- 重复合并直至单链表
- 虚拟头节点:
- 统一处理链表头节点
- 简化边界条件处理
关键洞察
- 分治效率核心:
- 两两合并避免高复杂度
- 合并次数从O(k)降为O(log k)
- 堆选择原理:
- 堆优化最小节点获取效率
- 每次操作时间复杂度O(log k)
- 空间复杂度对比:
- 分治法仅需递归栈空间
- 堆方法需额外O(k)空间
- 合并顺序影响:
- 顺序合并会重复处理长链表
- 分治合并保证平衡处理
复杂度分析
方法 | 时间复杂度 | 空间复杂度 | 说明 |
---|---|---|---|
顺序合并 | O(k²·n) | O(1) | k为链表数,n为平均长度 |
分治合并 | O(kn log k) | O(log k) | 递归栈深度 |
堆(优先队列) | O(kn log k) | O(k) | 堆中最多存储k个节点 |
代码实现
/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } *//** * @param {ListNode[]} lists * @return {ListNode} */var mergeKLists = function (lists) {
if (lists.length === 0) return null; if (lists.length === 1) return lists[0];
const n = lists.length; const half = Math.floor(n / 2); let leftHead = mergeKLists(lists.slice(0, half)); let rightHead = mergeKLists(lists.slice(half));
let dummy = new ListNode(); let temp = dummy; while (leftHead && rightHead) { if (leftHead.val > rightHead.val) { temp.next = rightHead; rightHead = rightHead.next; } else { temp.next = leftHead; leftHead = leftHead.next; } temp = temp.next; }
temp.next = leftHead || rightHead;
return dummy.next;};
实际应用场景
- 多路归并排序:外部排序中的多路归并`
- 任务调度:合并多个有序任务队列`
- 数据库优化:合并多个索引列表`
- 日志系统:合并多个来源的有序日志`
变种:迭代分治合并
const mergeKListsIterative = (lists) => { if (!lists.length) return null; while (lists.length > 1) { const mergedLists = []; for (let i = 0; i < lists.length; i += 2) { const l1 = lists[i]; const l2 = i + 1 < lists.length ? lists[i + 1] : null; mergedLists.push(mergeTwoLists(l1, l2)); } lists = mergedLists; } return lists[0];};// 空间复杂度优化为O(1)
function mergeTwoLists(head1,head2){ const dummy = new ListNode(); let temp = dummy,temp1= head1,temp2 = head2; while(temp1&&temp2){ if(temp1.val<temp2.val){ temp.next = temp1; temp1 = temp1.next }else{ temp.next = temp2; temp2 = temp2.next } temp = temp.next; } temp.next = temp1 || temp2; return dummy.next;}
相似题目
- [[合并两个有序链表]]
- 丑数 II
- 按位或最大的最小子数组长度