1 题目
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2 Java
2.1 方法一(归并链表)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public static ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
return mergeKListsCut(lists, 0, lists.length - 1);
}
// 分
public static ListNode mergeKListsCut(ListNode[] lists, int begin, int end) {
if (begin == end) {
return lists[begin];
}
int mid = (begin + end) / 2;
ListNode l1 = mergeKListsCut(lists, begin, mid);
ListNode l2 = mergeKListsCut(lists, mid + 1, end);
return mergeKListsMerge(l1, l2);
}
// 治;21. 合并两个有序链表
public static ListNode mergeKListsMerge(ListNode l1, ListNode l2) {
ListNode l = new ListNode(0);
ListNode head = l;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
l.next = l1;
l1 = l1.next;
l = l.next;
} else {
l.next = l2;
l2 = l2.next;
l = l.next;
}
}
l.next = (l1 != null) ? l1 : l2;
return head.next;
}
}
2.2 方法二(k指针)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public static ListNode mergeKLists(ListNode[] lists) {
ListNode l = new ListNode(0);
ListNode head = l;
// 直至所有链表都遍历完成,才结束循环
while (true) {
// 遍历所有链表头结点,记录 val 最小的头节点,及其所处链表的序号(索引)
ListNode minNode = new ListNode(Integer.MAX_VALUE);
int minNodePointer = -1;
for (int i = 0; i < lists.length; i++) {
// 跳过已遍历完的链表
if (lists[i] == null) {
continue;
}
if (lists[i].val <= minNode.val) {
minNode = lists[i];
minNodePointer = i;
}
}
// 若 minNode 未更新,即所有链表都遍历完成,结束循环
if (minNodePointer == -1) {
break;
}
// 已知最小头节点,将其挂在链表 l 的尾部
l.next = minNode;
l = l.next;
lists[minNodePointer] = lists[minNodePointer].next;
}
return head.next;
}
}
2.3 方法三(最小堆)
方法二的优化
维护一个 k 个链表头节点的最小堆,避免每次加入新节点时,都需要遍历 k 个链表 以获取最小头节点
PS:本题每次取一个最小值,适合使用堆排序
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public static ListNode mergeKLists(ListNode[] lists) {
// 匿名内部类写法;小根堆
// PriorityQueue<ListNode> queue = new PriorityQueue<>(new Comparator<ListNode>() {
// @Override
// // <>内属性,o1、o2 属性保持一致
// public int compare(ListNode o1, ListNode o2) {
// return o1.val - o2.val;
// }
// });
// Lambda 写法
// PriorityQueue<ListNode> queue = new PriorityQueue<>((ListNode o1, ListNode o2) -> { return o1.val - o2.val; });
// Lambda 化简写法;用所有链表头节点 构建小根堆
PriorityQueue<ListNode> queue = new PriorityQueue<>((o1, o2) -> o1.val - o2.val);
for (ListNode list : lists) {
if (list != null) {
queue.add(list);
}
}
ListNode head = new ListNode(0);
ListNode cur = head;
// 每次弹出当前堆的最小节点
while (!queue.isEmpty()) {
// 用 cur 连接当前堆中的最小节点
cur.next = queue.poll();
cur = cur.next;
// 再将被连接节点的后一节点入堆
if (cur.next != null) {
queue.add(cur.next);
}
}
return head.next;
}
}