java
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0) {
return null;
}
PriorityQueue<ListNode> pq = new PriorityQueue<>((a, b) -> a.val - b.val);
for(ListNode node:lists) {
if(node != null) {
pq.add(node);//将每个链表的第一个节点插入到优先队列中,
//插入过程中优先队列会按照定义的优先级自动调整插入位置
}
}
ListNode dummy = new ListNode(0);
ListNode current = dummy;
while(!pq.isEmpty()) {
ListNode node = pq.poll();//最小的节点
current.next = node;
current = current.next;
if(node.next != null) {
pq.add(node.next);
}
}
return dummy.next;
}
}
这段代码的算法思想如下:
算法概述
题目要求合并 ( K ) 个已经升序排列的链表,输出一个合并后的有序链表。代码使用**优先队列(PriorityQueue)**来实现,以确保每次取出当前最小的节点,这样可以高效地合并多个链表。
具体步骤
-
初始化优先队列:
- 代码中使用了一个优先队列(最小堆),用于存储链表中的节点。由于 Java 的
PriorityQueue
默认是最小堆,存入的节点会按从小到大的顺序排列。 - 优先队列的比较方式为
a.val - b.val
,即按节点的值进行升序排序。
- 代码中使用了一个优先队列(最小堆),用于存储链表中的节点。由于 Java 的
-
将每个链表的头节点加入优先队列:
- 对于传入的每个链表,将其头节点加入优先队列。这样,优先队列中会保存每个链表的第一个节点,代表各个链表的最小值。
- 如果链表为空,则跳过该链表。
-
构建合并后的链表:
- 创建一个虚拟头节点(dummy node) ,目的是简化链表的构建过程,并最终返回
dummy.next
作为结果链表的头节点。 - 然后通过一个指针
current
来指向新链表的尾部节点,从而逐步构建合并后的链表。
- 创建一个虚拟头节点(dummy node) ,目的是简化链表的构建过程,并最终返回
-
合并过程:
- 循环从优先队列中取出最小的节点,将其连接到合并链表的尾部。
- 如果取出的节点有下一个节点,则将这个下一个节点加入优先队列,以确保优先队列中始终包含来自各链表的最小值节点。
- 重复上述过程,直到优先队列为空。
-
返回结果:
- 最后,返回
dummy.next
,即合并后的有序链表的头节点。
- 最后,返回
时间复杂度
该算法的时间复杂度为 ( O(N \log K) ):
- ( N ) 是所有链表节点的总数。
- ( K ) 是链表的数量。
- 由于每次插入和取出优先队列中的元素的时间复杂度是 ( O(\log K) ),整个过程需要 ( N \log K ) 的时间复杂度。
总结
这段代码通过优先队列实现了多链表的高效合并,每次从优先队列中取出最小节点并连接到结果链表上,从而保证了结果链表的有序性。这样就可以在相对较低的时间复杂度下完成 ( K ) 个有序链表的合并。