题目描述
合并 k
个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
样例
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
算法分析
- 1、一开始先用小根堆存储
k
个排序链表的头指针,每次操作后用小根堆维护k
个链表当前元素最小的指针,并以指针对应的值进行排序 - 2、操作过程中,当小根堆不为空时,堆顶元素即当前
k
个排序链表当前最小的元素的指针t
,将该值加入到dummy
链表的后面,并把t
指针往后走一位,使得t
指针指向的值变大,再加入到小根堆中
时间复杂度 $O(nlogk)$
n表示的是所有链表的总长度,k表示k个排序链表
Java 代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> q = new PriorityQueue<ListNode>((x,y) -> (x.val - y.val));
for(int i = 0;i < lists.length;i ++) if(lists[i] != null) q.add(lists[i]);
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while(!q.isEmpty())
{
ListNode t = q.poll();
cur.next = new ListNode(t.val);
//更新cur
cur = cur.next;
//将下一个位置放进堆中
t = t.next;
if(t != null) q.add(t);
}
return dummy.next;
}
}
PriorityQueue<ListNode> q = new PriorityQueue<ListNode>((x,y) -> (x.val - y.val));
这一句的lamda表达式不太理解,是小根堆这样写嘛😂
后面的部分是一个比较器,根据指针的
val
值进行从小到大排序您好, 想问问时间复杂度, $O(nlogk)$ 是怎么算出来的? 我这样子算, 算出来好像不太一样… $k$个链表, 每个链表长度$N$的话, 时间复杂度分析来看: 1.建堆: $k$个链表, 每个链表$N$个节点$kO(N)$ 2. $k$个链表, 每个链表$N$个结点入堆 和 出堆的时间复杂度都是: $kN⋅O(log(kN))$. 总共是: $O(kN)+2O(kN⋅log(kN))$这样分析对吗?
不好意思,原来有个位置笔误了
hh
,n
·表示的是所有链表的总长度,你的分析是有点问题的~首先有k
个链表,小根堆中存的是每个链表当前最小的元素,因此小根堆最多有k
个元素,每次操作时,从小根堆取出堆顶元素,维护小根堆,时间复杂度是$O(logk)$,让取出来的元素的同链表中的下一个元素进入小根堆,维护小根堆,时间复杂度是$O(logk)$,总共有n
个元素,因此最多操作n
次$2O(logk)$的操作,因此总的时间复杂度是$O(2nlogk)$,即$O(nlogk)$核心的思想是:将
k
个链表的当前最小的元素进入小根堆,最多k
个,不是把所有n
个元素都直接加进去非常感谢您的讲解, 我这里确实分析错误了orz.