题目描述
方法二: 分治合并,时间复杂度 O(nlogk)
- 时间复杂度分析
- 一共合并
logK
层 - 链表总长度为n,每一层都要合并n次,
- 一共合并
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) return null;
return mergeLists(lists, 0, lists.length - 1);
}
//分治
public ListNode mergeLists(ListNode[] lists, int start, int end) {
if (start == end) {
return lists[start];
}
int mid = (start + end) / 2;
// 先写mid - 1会overflow,why?
ListNode node1 = mergeLists(lists, start, mid); // 到这里,node1表示前半截,已经排好序
ListNode node2 = mergeLists(lists, mid + 1, end); // 到这里,node2表示后半截,已经排好序
return merge2Lists(node1, node2);
}
//合并两个升序链表
public ListNode merge2Lists(ListNode node1, ListNode node2) {
ListNode dummy = new ListNode(-1);
ListNode cur = dummy;
while (node1 != null && node2 != null) {
if (node1.val <= node2.val) {
cur.next = node1;
node1 = node1.next;
} else {
cur.next = node2;
node2 = node2.next;
}
cur = cur.next;
cur.next = null;
}
cur.next = node1 == null ? node2 : node1;
return dummy.next;
}
}
如果merge的分割条件写成这样,会stackoverflow
ListNode l1 = merge(lists, start, (start + end) / 2 - 1);
ListNode l2 = merge(lists, (start + end) / 2, end);
- 典型错误:
方法三:维护一个大小为k的优先队列 O(NlogK)
- // 维护一个大小为k的小顶堆,由未合并的链表头节点构成
- // 每次选出k个节点中最小的,接在新链表后
- // 维护堆的复杂度logk,一共n,所以nlogk
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode dummy = new ListNode();
ListNode cur = dummy;
Queue<ListNode> pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);
// k个链表头节点入队列
for (ListNode list : lists) {
if (list != null) {
pq.offer(list);
}
}
while (!pq.isEmpty()) {
ListNode minNode = pq.poll();// 取出最小的
cur.next = minNode;//接上
cur = cur.next;
if (minNode.next != null) {
pq.offer(minNode.next);//入新的节点
}
}
return dummy.next;
}
}
方法一 :逐个合并、添加,复杂度略高
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode res = null;//结果链表,一开始为null
//第i次循环把第i个链表和res合并,答案保存到res中
for (ListNode x : lists) {
res = mergeTwoLists(res, x);
}
return res;
}
//合并两个升序链表
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode();
ListNode cur = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
cur.next = l1;
l1 = l1.next;
} else {
cur.next = l2;
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return dummy.next;
}
}