给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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个元素中找最小值,那么我们可以知道找最小值需要通过小顶堆来实现。
- 首先先把k个链表的头节点放到小顶堆中
- 设置一个虚拟头节点来维护最后合并链表的头节点
- 当小顶堆不为空时,每次从堆中取一个链表,将这个链表的头节点放到虚拟头节点链表的尾部
- 如果这个链表还有下一个节点,则将这个链表头节点的下一个节点放到堆中,否则不需要
- 重复上述2-4过程直到堆为空,返回虚拟头节点后的链表
代码
class Heap {
constructor() {
this.data = [];
}
swap(i, j) {
[this.data[i], this.data[j]] = [this.data[j], this.data[i]]
}
compartor(i, j) {
return this.data[i].val - this.data[j].val;
}
size() {
return this.data.length;
}
peek() {
if (!this.size()) return null;
return this.data[0]
}
offer(val) {
this.data.push(val);
this.bubbleUp(this.data.length-1);
}
pop() {
if (!this.size()) return null;
let res = this.data[0];
if (this.size() > 1) {
this.data[0] = this.data.pop();
this.bubbleDown(0);
} else {
this.data.pop();
}
return res;
}
bubbleUp(index) {
while(index) {
let parent = (index - 1) >> 1;
if (this.compartor(index, parent) < 0) {
this.swap(index, parent);
index = parent;
} else {
break;
}
}
}
bubbleDown(index) {
let last = this.data.length - 1;
while(index < last) {
let temp = index, left = index * 2 + 1, right = index * 2 + 2;
if (left <= last && this.compartor(left, temp) < 0) {
temp = left;
}
if (right <= last && this.compartor(right, temp) < 0) {
temp = right;
}
if (temp == index) break;
this.swap(temp, index);
index = temp;
}
}
}
var mergeKLists = function(lists) {
let h = new Heap()
for (const head of lists) {
if (head == null) continue
h.offer(head)
}
let ret = new ListNode(-1), p = ret
while(h.size() > 0) {
let cur = h.pop()
p.next = cur
p = cur
if (cur.next) h.offer(cur.next)
}
return ret.next
};