一、题目
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
二、思路及代码实现
思路一:分治法(两两合并)
假设有 n 个链表,先两两合并,list0 与 list1 合并,list2 与 list3 合并,……得到 n 2 \frac{n}{2} 2n 个链表;再两两合并,得到 n 4 \frac{n}{4} 4n 个链表;……最后得到的一个链表就是最终的结果。
合并两个链表有递归和迭代两种方法,参考
21. 合并两个有序链表
参考代码:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0)
return null;
return merge(lists, 0, lists.length - 1);
}
public ListNode merge(ListNode[] lists, int left, int right){
// lists中只有一个链表,直接返回该链表
if(left == right)
return lists[left];
int mid = left + (right - left) / 2;
ListNode l1 = merge(lists, left, mid);
ListNode l2 = merge(lists, mid + 1, right);
return mergeTwoLists(l1, l2);
}
public ListNode mergeTwoLists(ListNode l1, ListNode 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;
}
}
}
思路二:优先级队列
- 建立优先级队列(使用最小堆),将所有链表的头元素入队;
- 每次弹出一个最小的元素,并将该链表指针往后移;
- 队列元素全部弹出时结束。
参考代码:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0)
return null;
// 创建优先级队列(最小堆)
PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>(){
@Override
public int compare(ListNode l1, ListNode l2){
if(l1.val < l2.val)
return -1;
else if(l1.val == l2.val)
return 0;
else
return 1;
}
});
for(ListNode node : lists){
if(node != null)
queue.add(node);
}
// 合并
ListNode result = new ListNode(0);
ListNode p = result;
while(!queue.isEmpty()){
p.next = queue.poll();// 弹出最小元素
p = p.next;
if(p.next != null)
queue.add(p.next);
}
return result.next;
}
}