1.问题描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4
解题思路:
本题有多种解题思路。
如顺序合并,即最朴素的方法:用一个变量 ans 来维护以及合并的链表,第 ii 次循环把第 ii 个链表和 ans 合并,答案保存到 ans 中。使用到了两两归并的过程,但是时间复杂度会达到O(k2n)
还有一种是使用分治算法,但过程较为复杂
本文仅介绍一种时间复杂度较优,且实现非常容易的算法,即借助Java的优先级队列,Java优先级队列的具体介绍请参看:Java优先级队列PriorityQueue将K个链表中的所有结点全部入队,然后每次从队列中取出队头元素,即队列中的最小元素使用尾插法插入到虚拟头结点的后面。最终就可以将原K个链表按照从小到大的顺序排序。时间复杂度O(nlogn),但空间复杂度也为O(n)
实现代码:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
//创建优先级队列,传入一个比较器,比较器和优先级队列的参数都是ListNode
Queue<ListNode> pqueue=new PriorityQueue<ListNode>(new Comparator<ListNode>(){
@Override
//实现Comparator接口的compare方法。两个listNode排序时按照val值
public int compare(ListNode o1, ListNode o2) {
return o1.val-o2.val;
}
});
//遍历K个升序链表,将其全部加入到优先级队列中
for(ListNode li:lists){
ListNode p=li;
while(p!=null){
pqueue.offer(p);
p=p.next;
}
}
ListNode head=new ListNode(-1); //创建虚拟头结点
//我们使用的尾插法,尾插法能够保证元素按照插顺序进行组织,所以要维护一个尾结点
ListNode r=head;
//每次将优先级队列中的队头元素取出,加入到链表中
while(!pqueue.isEmpty()){
ListNode p=pqueue.poll();
r.next=p;
r=r.next;
}
//最终一定要将r.next置为空,否则可能会发生错误
r.next=null;
return head.next; //返回虚拟头结点的next指针。
}
}