给定一个链表数组,每个链表都已经按升序排列。要求将所有链表合并为一个升序链表,并返回合并后的链表头节点。
算法思路
可以使用分治法或优先队列(最小堆)来解决这个问题。这里使用优先队列(最小堆)来高效地合并多个有序链表:
- 优先队列:
- 将所有链表的头节点放入优先队列中,队列会根据节点的值进行排序。
- 每次从队列中取出最小的节点,将其添加到结果链表中,并将该节点的下一个节点(如果存在)放入队列中。
- 重复上述过程,直到队列为空。
Java实现
import java.util.PriorityQueue;
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) {
return null;
}
PriorityQueue<ListNode> queue = new PriorityQueue<>((a, b) -> a.val - b.val);
for (ListNode node : lists) {
if (node != null) {
queue.offer(node);
}
}
ListNode dummy = new ListNode(-1);
ListNode current = dummy;
while (!queue.isEmpty()) {
ListNode node = queue.poll();
current.next = node;
current = current.next;
if (node.next != null) {
queue.offer(node.next);
}
}
return dummy.next;
}
}
代码解释
- PriorityQueue:
- 使用优先队列来存储链表节点,队列根据节点的值进行排序。
- 初始化时,将所有非空链表的头节点加入队列。
- 合并过程:
- 创建一个虚拟头节点
dummy
和当前节点current
。 - 每次从队列中取出最小节点,将其连接到
current.next
,并移动current
。 - 如果取出的节点有下一个节点,将其加入队列。
- 创建一个虚拟头节点
- 返回结果:
- 最终返回
dummy.next
,即合并后的链表头节点。
- 最终返回
复杂度分析
- 时间复杂度:O(N log k),其中 N 是所有链表节点的总数,k 是链表的数量。每次插入和取出操作的时间复杂度为 O(log k)。
- 空间复杂度:O(k),优先队列最多存储 k 个节点。
简单总结
通过优先队列(最小堆)高效地合并多个有序链表,每次取出最小节点并更新队列,最终得到一个有序链表。算法的时间复杂度为 O(N log k),适用于链表数量较多的情况。