一、题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
二、示例
//示例一:
输入: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
//示例二
输入:lists = []
输出:[]
//示例三
输入:lists = [[]]
输出:[]
三、本题思路
本题我们可以采用最小堆
来解决该问题。
但是什么是最小堆:最小堆就是一个树形结构,父节点的元素的值要小于等于左右子树节点的值。
,在js
中我们使用数组
来表示。
本题为什么可以采用最小堆?
例如:[[1,4,5],[1,3,4],[2,6]]
,我们首先先取出[1, 4, 5]
,因为其第一个元素最小,将其第一个元素1
,接入新链表中。此时最小堆中的元素为[[1, 3, 4],[2, 6],[4, 5]]
,然后再取出[1, 3, 4]
,并将1
取出接入新链表。此时最小堆中的元素为[2, 6],[2, 4], [4, 5]
,然后再取出2…。
四、最小堆结构实现
class MinHeap {
constructor() {
this.heap = []
}
// 获取父元素的下标
getParentIndex(index) {
return (index - 1) >> 1
}
// 交换数据
swap(index1, index2) {
let temp = this.heap[index1]
this.heap[index1] = this.heap[index2]
this.heap[index2] = temp
}
// 向上移动数据,将目标数据放到合适的位置
shiftUp(index) {
if (index === 0) return
let parentIndex = this.getParentIndex(index)
if (this.heap[parentIndex] > this.heap[index]) {
this.swap(index, parentIndex)
this.shiftUp(parentIndex)
}
}
// 插入数据
insert(value) {
this.heap.push(value)
this.shiftUp(this.heap.length - 1)
}
// 从heap中取出最小的数
pop() {
if (this.size() === 1) return this.heap.shift()
let head = this.heap[0]
this.heap[0] = this.heap.pop()
this.shiftDown(0)
return head
}
// 下标为index的节点放入合适的位置
shiftDown(index) {
let leftChildIndex = this.getLeftChildIndex(index)
let rightChildIndex = this.getRightChildIndex(index)
if (this.heap[leftChildIndex] < this.heap[index]) {
this.swap(index, leftChildIndex)
this.shiftDown(leftChildIndex)
}
if (this.heap[rightChildIndex] < this.heap[index]) {
this.swap(index, rightChildIndex)
this.shiftDown(rightChildIndex)
}
}
// 获取左节点的index
getLeftChildIndex(index) {
return index * 2 + 1
}
// 获取右节点的index
getRightChildIndex(index) {
return index * 2 + 2
}
// 获取长度
size() {
return this.heap.length
}
}
let p = new MinHeap()
p.insert(10)
p.insert(1)
p.insert(3)
p.insert(4)
p.insert(9)
console.log(p)
p.pop()
console.log(p)
p.pop()
console.log(p)
五、本题代码实现
class MinHeap {
constructor() {
this.heap = []
}
// 获取父元素的下标
getParentIndex(index) {
return (index - 1) >> 1
}
// 交换数据
swap(index1, index2) {
let temp = this.heap[index1]
this.heap[index1] = this.heap[index2]
this.heap[index2] = temp
}
// 向上移动数据,将目标数据放到合适的位置
shiftUp(index) {
if (index === 0) return
let parentIndex = this.getParentIndex(index)
if ( this.heap[index] && this.heap[parentIndex] && this.heap[parentIndex].val > this.heap[index].val) {
this.swap(index, parentIndex)
this.shiftUp(parentIndex)
}
}
// 插入数据
insert(value) {
this.heap.push(value)
this.shiftUp(this.heap.length - 1)
}
// 从heap中取出最小的数
pop() {
if (this.size() === 1) return this.heap.shift()
let head = this.heap[0]
this.heap[0] = this.heap.pop()
this.shiftDown(0)
return head
}
// 下标为index的节点放入合适的位置
shiftDown(index) {
let leftChildIndex = this.getLeftChildIndex(index)
let rightChildIndex = this.getRightChildIndex(index)
if (this.heap[index] && this.heap[leftChildIndex] && this.heap[leftChildIndex].val < this.heap[index].val) {
this.swap(index, leftChildIndex)
this.shiftDown(leftChildIndex)
}
if (this.heap[index] && this.heap[rightChildIndex] && this.heap[rightChildIndex].val < this.heap[index].val) {
this.swap(index, rightChildIndex)
this.shiftDown(rightChildIndex)
}
}
// 获取左节点的index
getLeftChildIndex(index) {
return index * 2 + 1
}
// 获取右节点的index
getRightChildIndex(index) {
return index * 2 + 2
}
// 获取长度
size() {
return this.heap.length
}
}
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
let p = new ListNode(0)
let res = p
let heap = new MinHeap()
for(let item of lists) {
if(item) heap.insert(item)
}
while(heap.size()) {
let n = heap.pop()
p.next = n
p = p.next
if(n.next) {
heap.insert(n.next)
}
}
return res.next
};
六、总结