这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 == lists.length0 <= k <= 10^40 <= lists[i].length <= 500-10^4 <= lists[i][j] <= 10^4lists[i]按 升序 排列lists[i].length的总和不超过10^4
解题思路
思路1:双指针法 + 两两合并
- 时间复杂度:O(kn)(k为链表个数,n为当前两个合并中链表的长度)
- 空间复杂度:O(1)
- 区别
- 不止两个链表
- 两两合并
- 遍历数组,合并两个成新的一个链表再继续合并下一个链表
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
let mergeTwoLists = (l1,l2) => {
let preHead = new ListNode(-1)
let preNode = preHead
while(l1 && l2){
if(l1.val <= l2.val){
preNode.next = l1
l1 = l1.next
}else{
preNode.next = l2
l2 = l2.next
}
preNode = preNode.next
}
preNode.next = l1 ? l1 : l2
return preHead.next
}
let n = lists.length
if(n == 0) return null
let res = lists[0]
for(let i = 1;i < n;i++){
if(lists[i]){
res = mergeTwoLists(res,lists[i])
}
}
return res
};
思路2:递归 + 分治
- 时间复杂度:O(nlogK)
- k为链表总数
- n为合并两个链表所用时间
- 空间复杂度:O(n)
- 分治
- 借用官方一张图说明分治合并过程
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
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);
};
思路3:优先级队列
- 参考大佬的
- 时间复杂度:O(Nlogk)
- k为链表数目
- 弹出操作时,比较操作为O(logK)
- 找最小值操作为O(1)
- N为链表元素总数和
- 空间复杂度:O(n+k)
- n为创建新链表开销
- k为额外队列开销
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
let queue = new PriorityQueue();
lists.forEach(list => {
if(list) queue.enqueue(list, list.val)
});
let res = new ListNode(-1);
let cur = res;
while(!queue.isEmpty()) {
cur.next = queue.dequeue();
cur = cur.next;
if(cur.next) queue.enqueue(cur.next, cur.next.val);
}
return res.next;
}
class Node {
constructor(val, priority) {
this.val = val;
this.priority = priority;
}
}
class PriorityQueue {
constructor() {
this.values = [];
}
enqueue(val, priority) {
let node = new Node(val, priority);
this.values.push(node);
this.bubbleUp();
}
dequeue() {
let max = this.values[0];
let end = this.values.pop();
if(this.values.length) {
this.values[0] = end;
this.bubbleDown();
}
return max.val;
}
isEmpty() {
return !this.values.length;
}
bubbleUp(index = this.values.length - 1) {
if(index <= 0) return;
let parentIndex = Math.floor((index - 1) / 2);
if(this.values[index].priority <= this.values[parentIndex].priority) {
[this.values[index], this.values[parentIndex]] = [this.values[parentIndex], this.values[index]];
this.bubbleUp(parentIndex);
}
}
bubbleDown(index = 0, swapIndex = null) {
let leftIndex = index * 2 + 1,
rightIndex = index * 2 + 2,
length = this.values.length;
if(leftIndex < length) {
if(this.values[leftIndex].priority <= this.values[index].priority) {
swapIndex = leftIndex;
}
}
if(rightIndex < length) {
if((swapIndex === null && this.values[rightIndex].priority <= this.values[index].priority) || (swapIndex !== null && this.values[rightIndex].priority <= this.values[leftIndex].priority)) {
swapIndex = rightIndex;
}
}
if(swapIndex !== null) {
[this.values[index], this.values[swapIndex]] = [this.values[swapIndex], this.values[index]];
this.bubbleDown(swapIndex, null);
}
}
};
思路4:数组
- 时间复杂度:O(NlogN)
- N:节点总数
- O(N):遍历开销
- O(NlogN):排序(假设稳定)
- O(N):创建新的有序链表
- 空间复杂度:O(N)
- O(N):排序
- O(N):创建新的有序链表
- 思路
- 遍历所有链表元素,将元素值放到一个数组中
- 排序数组,相当于按优先级排序优先级队列
- 遍历排好序的数组,重新构造一个新的有序链表即为所求
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function(lists) {
if(!lists || lists.length == 0) return null;
let arr = [];
let res = new ListNode(0);
lists.forEach(list => {
let cur = list;
while(cur){
arr.push(cur.val);
cur = cur.next;
}
})
let cur = res;
arr.sort((a,b) => a-b).forEach(val => {
let node = new ListNode(val);
cur.next = node;
cur = cur.next;
})
return res.next;
};
最后
曾梦想仗剑走天涯
看一看世界的繁华
年少的心总有些轻狂
终究不过是个普通人
无怨无悔我走我路
「前端刷题」No.23