本文正在参与掘金团队号上线活动,点击 查看大厂春招职位
一、题目描述:
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
二、思路分析:
本道题的前置题目:合并两个升序链表其实是很简单的,只要比较两个链表的当前节点谁小就可以了,但是要合并K个就不太容易了,或者说写个时间复杂度不太糟糕的算法不太容易,主要问题是比较这K个链表的当前节点用什么方法比较合适,想了一下,想到的方法要么慢,要么不太容易优雅地实现,果断去瞄了眼讨论,果然大多数讨论是关于优先队列的,优先队列其实是堆的一个特例,然而平时不用,想不到,而js中没有现成的优先队列与堆的实现导致js解法还是以递归分治为主。以下是官方题解示意图:
综合考虑我还是觉得优先队列的方法最优雅,可能是由于我对于堆的偏爱吧。但是由于额外实现优先队列篇幅太长,贴个分治的AC解法
三、AC代码:
var mergeKLists = function(lists) {
let n = lists.length;
if(n == 0) return null;
let mergeTwoLists = (l1,l2) => {
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val <= l2.val){
l1.next = mergeTwoLists(l1.next,l2);
return l1;
}else{
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
let merge = (left,right) => {
if(left == right) return lists[left];
let mid = (left + right) >> 1;
let l1 = merge(left,mid);
let l2 = merge(mid+1,right);
return mergeTwoLists(l1,l2);
}
return merge(0,n-1);
};
四、总结:
var mergeKLists = function(lists) {
return lists.reduce((p, n) => {
while (n) {
p.push(n), n = n.next
}
return p
},[]).sort((a, b) => a.val - b.val).reduceRight((p, n) => (n.next = p, p = n, p), null)
};