LeetCode 23. 合并 K 个升序链表 ------ 小顶堆(PriorityQueue)
📌 题目链接
💡 解题思路
本题是 21. 合并两个有序链表 的进阶版。
暴力思路(不推荐)
- 两两合并:
O(kN) - 效率低,容易超时
java
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) {
return null;
}
if(lists.length == 1) {
return lists[0];
}
ListNode res = new ListNode();
res = merge(lists[0], lists[1]);
for(int i=2;i<lists.length;i++) {
res = merge(res, lists[i]);
}
return res;
}
public ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode();
ListNode cur = dummy;
while(l1!=null && l2!=null) {
if(l1.val < l2.val) {
cur.next = l1;
l1=l1.next;
} else {
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1!=null ? l1 : l2;
return dummy.next;
}
}
最优思路:小顶堆(优先队列)
核心思想:
每次只取 当前所有链表头部最小的节点
具体做法:
- 将所有链表的头结点加入 小顶堆
- 每次从堆中取出最小节点,接到结果链表
- 若该节点还有后继节点,将其加入堆
- 重复直到堆为空
🛠 关键技术点
1️⃣ 使用 PriorityQueue 构建小顶堆
java
PriorityQueue<ListNode> pq =
new PriorityQueue<>((a, b) -> a.val - b.val);
- Java 默认是最小堆
- 按
val从小到大排序
2️⃣ 初始化堆
java
for (ListNode node : lists) {
if (node != null) {
pq.offer(node);
}
}
- 只放非空链表
- 堆中最多同时存在
k个节点
3️⃣ 动态维护堆
java
ListNode node = pq.poll();
if (node.next != null) {
pq.offer(node.next);
}
📌 关键点:
- 每取出一个节点,就补一个它的后继节点进堆
- 保证堆中始终是各链表当前的"最小值候选"
🧩 完整代码(Java)
java
/**
* Definition for singly-linked list.
*/
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
// 1. 最小堆(按节点值排序)
PriorityQueue<ListNode> pq =
new PriorityQueue<>((a, b) -> a.val - b.val);
// 2. 所有链表的头结点入堆
for (ListNode node : lists) {
if (node != null) {
pq.offer(node);
}
}
// 3. 构造结果链表
ListNode dummy = new ListNode();
ListNode cur = dummy;
while (!pq.isEmpty()) {
ListNode node = pq.poll();
if (node.next != null) {
pq.offer(node.next);
}
cur.next = node;
cur = cur.next;
}
return dummy.next;
}
}
⏱ 复杂度分析
| 指标 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(N log k) | N 为总节点数,k 为链表个数 |
| 空间复杂度 | O(k) | 堆中最多存放 k 个节点 |
✅ 总结
- ✅ 最小堆写法 逻辑最清晰、最好写
- ✅ 面试中极其常见,属于必会题
- ⚠️ 若要求 O(1) 空间 ,可使用 分治法(类似归并排序)
一句话总结:
K 路归并,堆中永远只保留"下一个可能的最小值"。