Merge k Sorted Lists 合并 K 个升序链表
问题描述:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
k = = l i s t s . l e n g t h 0 < = k < = 1 0 4 0 < = l i s t s [ i ] . l e n g t h < = 500 − 1 0 4 < = l i s t s [ i ] [ j ] < = 1 0 4 l i s t s [ i ] 按升序排列 l i s t s [ i ] . l e n g t h 的总和不超过 1 0 4 k == lists.length\\ 0 <= k <= 10^4\\ 0 <= lists[i].length <= 500\\ -10^4 <= lists[i][j] <= 10^4\\ lists[i] 按 升序 排列\\ lists[i].length 的总和不超过 10^4 k==lists.length0<=k<=1040<=lists[i].length<=500−104<=lists[i][j]<=104lists[i]按升序排列lists[i].length的总和不超过104
分析
要求非常简单,就是把多个有序链表合并成为一个有序链表。
这里有k个链表,以之前的经验,可以相邻的2个合并,假设链表的平均长度都是L,那么按照这个方式处理,需要合并k-1次,第一次的平均时间复杂度为
O
(
2
L
)
O(2L)
O(2L),第二次的时间复杂度为
O
(
3
L
)
O(3L)
O(3L),所以第k-1次的时间复杂度就是
O
(
(
k
−
1
)
L
)
O((k-1)L)
O((k−1)L).
所以在这个思路下的时间复杂度就是
O
(
(
k
2
)
N
)
O((k^2)N)
O((k2)N),但是好处是空间是
O
(
1
)
O(1)
O(1).
思路没有大问题,但是数据规模大的情况下,这个时间复杂度并不友好。
为什么这个思路下的时间复杂度会达到K^2,你细品。
既然每个链表都是有序的,那么可以从k个节点中找到最小的加入最终结果的尾部。
如果是朴素的找法,从k个节点找最小的,单次耗时
O
(
k
)
,
O(k),
O(k),一共有kL个节点,时间复杂度也是
O
(
(
K
2
)
N
)
O((K^2)N)
O((K2)N)。
如果利用有序的特殊条件,可以找到对数时间复杂度的方法,比如分治归并,或者是小顶堆。
在不同的角度上降低了时间复杂度。
- 分治归并与原本的归并比较起来,它只需要合并 l o g K logK logK次。
- 小顶堆的思路,则是可以在 l o g K logK logK的时间复杂度下,找到最小的节点。
目前没有比这2个思路更快的,时间复杂度都是 O ( N K l o g K ) , O(NKlogK), O(NKlogK),但是空间复杂度一个是 O ( l o g K ) O(logK) O(logK),一个是 O ( K ) O(K) O(K).
代码
Heap
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> pq = new PriorityQueue<ListNode>((a,b)->{return a.val-b.val;});
ListNode h = new ListNode(0);
for(ListNode no: lists){
if(no==null) continue;
pq.offer(no);
}
ListNode p = h;
while(!pq.isEmpty()){
ListNode cur = pq.poll();
ListNode nx = cur.next;
p.next = cur;
p = cur;
if(nx!=null) pq.offer(nx);
}
return h.next;
}
时间复杂度 O ( N K l o g K ) O(NKlogK) O(NKlogK)
空间复杂度 O ( K ) O(K) O(K)
Tag
Heap
文章来源:https://www.toymoban.com/news/detail-643864.html
Merge Sort
文章来源地址https://www.toymoban.com/news/detail-643864.html
到了这里,关于【LeetCode 算法】Merge k Sorted Lists 合并 K 个升序链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!