合并K个有序链表
Wallace Xu 2020-09-25 递归优先队列
# LeetCode 23. 合并K个升序链表 (opens new window)
# 题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
# 示例
输入: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
输入:lists = []
输出:[]
输入:lists = [[],[]]
输出:[]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 解题思路
我们可以先解决合并两个有序链表的问题,和归并两个有序数组相同,可以使用双指针。我这里为了看起来简洁使用了递归的方法,会使用到O(n)的递归栈空间。
对于头结点保存在数组中的K个链表,我们也可以使用递归的方法,合并两半子数组合并后的链表,递归终止的条件是数组为空或者数组长度小于等于2。
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
if (lists.length == 1) return lists[0];
if (lists.length == 2) return merge2Lists(lists[0], lists[1]);
return merge2Lists(mergeKLists(Arrays.copyOfRange(lists, 0, lists.length / 2)), mergeKLists(Arrays.copyOfRange(lists, lists.length / 2, lists.length)));
}
private ListNode merge2Lists(ListNode head1, ListNode head2) {
if (head1 == null) return head2;
if (head2 == null) return head1;
if (head1.val <= head2.val) {
head1.next = merge2Lists(head1.next, head2);
return head1;
} else {
head2.next = merge2Lists(head1, head2.next);
return head2;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
除了两两归并的思路外,我们还可以使用大小为K的优先队列来直接管理K个链表当前处理到的节点间的大小关系。
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> heap = new PriorityQueue<>((a, b) -> a.val - b.val);
for (ListNode node : lists)
if(node != null) heap.offer(node);
ListNode dummy = new ListNode(), pointer = dummy;
while (!heap.isEmpty()) {
ListNode min = heap.poll();
if (min.next != null) heap.offer(min.next);
pointer.next = min;
pointer = pointer.next;
}
return dummy.next;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13