做了一张好丑的图
正题
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入: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
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
合并K个升序链表,可以看做是 合并两个升序链表 的衍生,具体如何实现可以参阅之前的合并两个升序链表的文章。
有了这个基础,这个问题解决起来就容易多了,我们可以有:
方法一:顺序合并两个链表
也可以称之为两两合并,通过数组 pop() 出一个一个链表然后合并,这样就拆解成了 n-1 次的 合并两个升序链表的问题了,这样问题是不是就迎刃而解了?
const mergeTwoLists = (n1, n2) => {
let res = new ListNode(0) //创建虚拟节点
let p = res // res 指针
let p1 = n1 // L1 指针
let p2 = n2 // L2指针
while (p1 && p2) {
if (p1.val < p2.val) {
p.next = p1 // p指针指向 p1
p1 = p1.next // L1指针右移
} else {
p.next = p2 // p指针指向 p2
p2 = p2.next // L2指针右移
}
p = p.next // p 的指针右移
}
p.next = p1 ? p1 : p2 // 当前有一个链表已合并历完, p next 指针直接指向未合并的剩余链表的下一个元素
return res.next
}
var mergeKLists = function(lists) {
if (lists.length === 0) {
return new ListNode(null).next
}
let res = lists.pop()
while(lists.length) {
const l2 = lists.pop()
res = mergeTwoLists(res, l2)
}
return res
}
以上为顺序合并的代码,也非常好理解。
那么在我们两两合并链表的时候可以发现,是通过指针右移比较大晓得方式进行合并的,同样的,我们可以将此方法用于多个链表的合并,原理相同!
方法二: 多指针右移
如图可知,其实是和两个链表合并原理是一样的,不同的是需要在多个链表中记录下 val 最低的是哪个链表,然后将该链表指针右移,两个链表则直接比较就可以了。
var mergeKLists = function(lists) {
let res = new ListNode(0)
let resP = res
let flag = 0
lists = lists.filter(item => {
return item !== null
})
while(lists.length > 0) {
let selectIndex = 0
let minP = lists[selectIndex]
for (let index = 1 ; index < lists.length ; index++) {
if (lists[index].val < minP.val) {
minP = lists[index]
selectIndex = index
}
}
resP.next = lists[selectIndex]
resP = resP.next
lists[selectIndex] = lists[selectIndex].next
lists = lists.filter(item => {
return item !== null
})
}
return res.next
};
多个链表的升序合并实际上并不难,只要掌握两个链表的合并,无论是在此基础上叠加(方法一),还是利用相同原理(方法二)都可以很轻松解决,所以基础还是比较重要的。