23.合并K个升序链表
问题:给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例:
输入: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
思路:
方法一:用一个变量 res
来维护以及合并的链表,第 i 次循环把第 i个链表和 res
合并,答案保存到 res
中。
合并两个升序链表可参考24.合并两个升序链表。
代码如下:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
ListNode res = null;
for(int i = 0; i < lists.length; i++){
res = merge(res, lists[i]);
}
return res;
}
private ListNode merge(ListNode l1, ListNode l2){
if(l1 == null || l2 == null) return l1 == null ? l2 : l1;
ListNode head = new ListNode();
ListNode res = head;
//合并后的链表l1,有可能会比l2长,这里判断合并结束的条件为l2为空,然后将l1的剩余元素都插入到后面,
//时间上可能会比判断l1为空快一点
while(l2 != null){
if(l1 != null && l2.val > l1.val){
head.next = l1;
head = head.next;
l1 = l1.next;
} else {
head.next = l2;
head = head.next;
l2 = l2.next;
}
}
head.next = l1;
return res.next;
}
}
方法二:归并排序
是对方法一的优化,
- 将链表数组中的链表两两合并,这样原来的数组长度变为原来的一半,然后重复这一过程,直到我们将所有的链表都合并了
- 参考官方的图解
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null) return null;
return merge(lists, 0, lists.length - 1);
}
private ListNode merge(ListNode[] lists, int l, int r){
if(l == r) return lists[l];
if(l > r) return null;
int mid = l + (int) (r - l) / 2;
return mergeTwo(merge(lists, l, mid), merge(lists, mid + 1, r));
}
private ListNode mergeTwo(ListNode l1, ListNode l2){
if(l1 == null || l2 == null) return l1 == null ? l2 : l1;
ListNode head = new ListNode();
ListNode res = head;
while(l1 != null){
if(l2 != null && l1.val > l2.val){
head.next = l2;
head = head.next;
l2 = l2.next;
} else {
head.next = l1;
head = head.next;
l1 = l1.next;
}
}
head.next = l2;
return res.next;
}
}
方法三:优先队列(小顶堆)
首先将各个链表的头节点放入优先队列,此时队首为所有链表中最小的节点(因为这些链表都是升序的)。然后每次都取出最小的节点也就是优先队列队首节点插入新链表,再将这个节点的后继节点放入队列中,直到队列为空。
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
ListNode dummy = new ListNode(-1);
ListNode p = dummy;
PriorityQueue<ListNode> pQueue = new PriorityQueue<ListNode>(lists.length, (l1, l2) -> l1.val - l2.val);
for(ListNode head: lists){
if(head != null){
pQueue.offer(head);
}
}
while(!pQueue.isEmpty()){
ListNode min = pQueue.poll();
p.next = min;
if(min.next != null){
pQueue.offer(min.next);
}
p = p.next;
}
return dummy.next;
}
}
整理思路,记录博客,以便复习。若有误,望指正~