合并 K 个升序链表
描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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
分析
解法一:用小顶堆,初始化放入K个,然后依次取出堆顶元素,加入新链表,把取出来的元素的下个节点重新入堆。
解法二:分治法。
- 先对原问题进行拆分,每次数组进行对半拆分,直至只有一个链表,这是就可以返回
- 分别拿到左边和右边的有序链表,然后进行合并。(类似于归并排序的merge操作)
代码
解法一
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(o -> o.val));
for (ListNode head : lists) {
if (head != null) {
priorityQueue.offer(head);
}
}
ListNode listHead = new ListNode(-1, null);
ListNode tail = listHead;
while (!priorityQueue.isEmpty()) {
ListNode node = priorityQueue.poll();
tail.next = node;
tail = node;
if (node.next != null) {
priorityQueue.offer(node.next);
}
}
return listHead.next;
}
解法二
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
return process(0, lists.length - 1, lists);
}
//先分,后合并
public ListNode process(int start, int end, ListNode[] lists) {
if (start == end) {
return lists[start];
}
int mid = (start + end) / 2;
ListNode leftOrdered = process(start, mid, lists);
ListNode rightOrdered = process(mid + 1, end, lists);
return merge(leftOrdered, rightOrdered);
}
//合并操作
private ListNode merge(ListNode leftOrdered, ListNode rightOrdered) {
if (leftOrdered == null) {
return rightOrdered;
}
if (rightOrdered == null) {
return leftOrdered;
}
PriorityQueue<ListNode> heap = new PriorityQueue<>((o1, o2) -> o1.val - o2.val);
heap.add(leftOrdered);
heap.add(rightOrdered);
ListNode sentinel = new ListNode();
ListNode p = sentinel;
while (heap.size() > 0) {
ListNode node = heap.poll();
p.next = node;
p = node;
if (node.next != null) {
heap.add(node.next);
}
}
return sentinel.next;
}