function ListNode(val, next) {
this.val = (val === undefined ? 0 : val)
this.next = (next === undefined ? null : next)
}
var mergeKLists = function (lists) {
class PriorityQueue {
constructor(comparator = (a, b) => a < b) {
this._heap = [];
this._comparator = comparator;
}
_swap(i1, i2) {
[this._heap[i1], this._heap[i2]] = [this._heap[i2], this._heap[i1]];
}
_compare(i1, i2) {
return this._comparator(this._heap[i1], this._heap[i2]);
}
_parent(i) {
return Math.floor((i - 1) / 2);
}
_leftChild(i) {
return 2 * i + 1;
}
_rightChild(i) {
return 2 * i + 2;
}
size() {
return this._heap.length;
}
_shiftUp(i) {
let parent = this._parent(i);
if (parent >= 0 && this._compare(i, parent)) {
this._swap(i, parent);
this._shiftUp(parent);
}
}
_shiftDown(i) {
let leftChild = this._leftChild(i);
let rightChild = this._rightChild(i);
if (leftChild >= this.size()) return;
let min = leftChild;
if (rightChild < this.size() && !this._compare(leftChild, rightChild)) {
min = rightChild;
}
if (!this._compare(i, min)) {
this._swap(i, min);
this._shiftDown(min);
}
}
push(value) {
this._heap.push(value);
this._shiftUp(this._heap.length - 1);
}
peek() {
return this._heap[0];
}
pop() {
if (this.size() == 1) return this._heap.shift();
const top = this._heap[0];
this._heap[0] = this._heap[this._heap.length - 1];
this._heap.pop();
this._shiftDown(0);
return top;
}
}
lists = lists.filter(Boolean).filter(v => v.length != 0);
if (lists.length == 0) return null;
let pq = new PriorityQueue((a, b) => a.val > b.val);
for (const list of lists) {
pq.push(list);
}
let dummyHead = p = new ListNode(-1);
while (pq.size()) {
let top = pq.pop();
if (top && top.next) {
pq.push(top.next);
}
p.next = top;
p = p.next;
}
return dummyHead.next;
};
let lists = [[5, 4, 1], [4, 3, 1], [6, 2]];
let newLists = [];
lists.forEach((list) => {
let head = new ListNode(-1);
list.reduce((pre, now) => {
pre.next = new ListNode(now);
return pre.next;
}, head);
newLists.push(head.next);
});
function print(list) {
return JSON.stringify(list);
}
console.log(print(mergeKLists(newLists)));
- 利用自己实现的优先级队列,可以实现合并升序数组和降序数组两个类型的题目,只需要修改传入优先级队列的compare函数,和C++中优先级队列的使用方式一样。
- 另外一个注意点是,在_shiftDown的逻辑中,通过在每个节点选择较小/较大的子节点放到当前节点的位置上,之后再递归的向下调整,会比注释中的,先在左子树中调整,再调整右子树的逻辑,节省很多时间,因为节省掉了很多不必要的递归比较。

- btw,一些小trick:通过reduce将数组转换成ListNode;通过JSON.stringify将ListNode打印出来。
Reference
堆排序:原理与实现
拜托,面试别再问我堆(排序)了!