题目介绍
力扣23题:leetcode-cn.com/problems/me…
分析
合并k个有序链表的逻辑类似合并两个有序链表,难点在于,如何快速得到k个节点中的最小节点,接到结果链表上?
这里我们就要用到 [优先队列]这种数据结构,把链表节点放入一个最小堆,就可以每次获得k个节点中的最小节点:
代码如下:
/**
* 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) {
if(lists.length == 0) {
return null;
}
//哨兵节点,指向新链表头节点的上一个节点
ListNode preHead = new ListNode(-1);
ListNode pre = preHead;
//创建优先队列,使用小顶堆
PriorityQueue<ListNode> pq = new PriorityQueue<>(lists.length , (a,b) -> {
return a.val - b.val;
});
//将k个链表的头节点加入到小顶堆中
for(ListNode head : lists) {
if(head != null) {
//加入优先队列
pq.add(head);
}
}
while(!pq.isEmpty()) {
//获取小顶堆最小值,即堆顶元素
ListNode node = pq.poll();
pre.next = node;
if(node.next != null) {
pq.add(node.next);
}
//pre指针不断前进
pre = pre.next;
}
return preHead.next;
}
}
这个算法是面试常考题,它的时间复杂度是多少呢?
优先队列pq中的元素个数最多是k,所以一次poll或者add方法的时间复杂度是O(logk);所有的链表节点都会被加入和弹出pq,所以算法整体的时间复杂度是O(Nlogk),其中k是链表的条数,N是这些链表的节点总数。