题目描述
LeetCode 题目链接:合并 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
示例 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
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */
题解
遍历添加
这是“添油战术”,效率最低的
class Solution {
public static ListNode mergeTwoLists(ListNode p1, ListNode p2) {
if (p1 == null) return p2;
if (p2 == null) return p1;
ListNode sentinel = new ListNode(Integer.MIN_VALUE, null);
ListNode p = sentinel;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
p.next = p1;
p1 = p1.next;
} else {
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if (p1 == null) p.next = p2;
if (p2 == null) p.next = p1;
return sentinel.next;
}
public static ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length < 1) return null;
if (lists.length == 1) return lists[0];
ListNode t = lists[0];
for (int i = 1; i < lists.length; i++) {
t = mergeTwoLists(t, lists[i]);
}
return t;
}
}
递归分治
- 切分后两两合并,降低合并的次数与每次合并的时间成本
class Solution {
public static ListNode mergeTwoLists(ListNode p1, ListNode p2) {
if (p1 == null) return p2;
if (p2 == null) return p1;
ListNode sentinel = new ListNode(Integer.MIN_VALUE, null);
ListNode p = sentinel;
while (p1 != null && p2 != null) {
if (p1.val <= p2.val) {
p.next = p1;
p1 = p1.next;
} else {
p.next = p2;
p2 = p2.next;
}
p = p.next;
}
if (p1 == null) p.next = p2;
if (p2 == null) p.next = p1;
return sentinel.next;
}
private static ListNode split(ListNode[] listNodes, int l, int r) {
if (l == r) return listNodes[l]; // l == r 切分到只剩下一个
int m = (l + r) >>> 1;
ListNode leftList = split(listNodes, l, m);
ListNode rightList = split(listNodes, m + 1, r);
return mergeTwoLists(leftList, rightList);
}
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length < 1) return null;
if (lists.length == 1) return lists[0];
return split(lists, 0, lists.length - 1);
}
}
使用小根堆
class Solution {
static class SimpleMinHeap {
ListNode[] arr;
int size;
public SimpleMinHeap(int capacity) {
arr = new ListNode[capacity];
}
public boolean offer(ListNode offered) {
if (isFull()) {
return false;
}
int cur = size++;
int p = (cur - 1) >> 1;
while (cur > 0 && offered.val < arr[p].val) {
arr[cur] = arr[p];
cur = p;
p = (cur - 1) >> 1;
}
arr[cur] = offered;
return true;
}
public ListNode poll() {
if (isEmpty()) {
return null;
}
ListNode res = arr[0];
swap(0, --size);
arr[size] = null;
fall(0);
return res;
}
private void fall(int r) {
// bug int left = r << 1 + 1;
int left = (r<<1) +1;
int right = left + 1;
int min = r;
if (left < size && arr[left].val < arr[min].val) {
min = left;
}
if (right < size && arr[right].val < arr[min].val) {
min = right;
}
if (min != r) { // 被更新了
swap(min, r);
fall(min);
}
}
private void swap(int x1, int x2) {
ListNode t = arr[x1];
arr[x1] = arr[x2];
arr[x2] = t;
}
public boolean isEmpty() {
return size == 0;
}
public boolean isFull() {
return size >= arr.length;
}
}
public ListNode mergeKLists(ListNode[] lists) {
SimpleMinHeap heap = new SimpleMinHeap(lists.length);
/* 所有链表的头节点 加入到小顶堆 */
for (ListNode l : lists) {
if (l != null) {
heap.offer(l);
l = l.next;
}
}
// 构建新链表
ListNode sentinel = new ListNode(-1, null);
ListNode p = sentinel;
while (!heap.isEmpty()) {
// 拿出堆顶
ListNode min = heap.poll();
p.next = min;
p = min;
if (min.next != null) {
heap.offer(min.next);
}
p.next = null;
}
return sentinel.next;
}
}