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
Related Topics 堆 链表 分治算法
👍 1068 👎 0
2. 题解
2.1 题解1: 递归分治合并
/**
* 解法1 : 递归分治合并
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return merge(lists, 0, lists.length - 1);
}
/**
* 合并链表数组中 从 下标 start 到 下标 end 的链表
*
* @param lists
* @param start
* @param end
* @return
*/
public ListNode merge(ListNode[] lists, int start, int end) {
if (start == end) {
return lists[start];
}
// 终止条件
if (start > end) {
return null;
}
// 分而治之
int mid = start + (end - start) / 2;
ListNode h1 = merge(lists, start, mid);
ListNode h2 = merge(lists, mid + 1, end);
return mergeTwoList(h1, h2);
}
/**
* 合并两个有序链表
*
* @param h1
* @param h2
* @return
*/
public ListNode mergeTwoList(ListNode h1, ListNode h2) {
ListNode dummy = new ListNode(-1);
ListNode curr = dummy, p1 = h1, p2 = h2;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
curr.next = p1;
p1 = p1.next;
} else {
curr.next = p2;
p2 = p2.next;
}
curr = curr.next;
}
curr.next = p1 == null ? p2 : p1;
return dummy.next;
}
}
2.2 题解2. 优先队列
/**
* 解法2: 优先队列
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
ListNode dummy = new ListNode(0);
ListNode p = dummy;
// 将头结点都加入优先队列
for (int i = 0; i < lists.length; i++) {
if (lists[i] != null) {
queue.add(lists[i]);
}
}
while (!queue.isEmpty()) {
p.next = queue.poll();
p = p.next;
if (p.next != null) {
queue.add(p.next);
}
}
return dummy.next;
}
}
2.3 题解3 . 自底向上两两合并迭代
/**
* 解法3: 自底向上两两迭代
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
// 外层循环控制步长, 每次合并的结果都保存在 step 下标的位置
for (int step = 1; step < lists.length; step = step * 2) {
// 内层循环控制合并, 每次合并两个链表, 合并后的链表头保存在前面的下标位置
// 由于0乘原因, 只能通过 i 迭代访问后一个链表的下标
// 合并过程中, 两两合并, 所以下一次合并的链表在 2*step 之后
for (int i = step; i < lists.length; i += 2 * step) {
// 合并的第一个链表的下标为 i-step, 第二个为 i, 结果放入第一个中
lists[i - step] = mergeTwoList(lists[i - step], lists[i]);
lists[i] = null;
}
}
return lists[0];
}
/**
* 合并两个有序链表
*
* @param h1
* @param h2
* @return
*/
public ListNode mergeTwoList(ListNode h1, ListNode h2) {
ListNode dummy = new ListNode(0);
ListNode temp = dummy, p1 = h1, p2 = h2;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
temp.next = p1;
p1 = p1.next;
} else {
temp.next = p2;
p2 = p2.next;
}
temp = temp.next;
}
temp.next = p1 == null ? p2 : p1;
return dummy.next;
}
}