问题
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
例子
思路
-
方法1
-
遍历链表数组,顺序取出链表和head合并
-
方法2
-
归并分治的方法,一次合并2i和2i+1,并放在i下标【如果为奇数lists[len/2]=lists[len-1]】最后返回lists[0]
-
方法 总共n个元素,k个链
** 逐一合并**
2 n k + 3 n k + . . + k n k = n k × k 2 2 = O ( n k ) 2\frac{n}{k}+3\frac{n}{k}+..+k\frac{n}{k}=\frac{n}{k}\times\frac{k^2}{2}=O(nk) 2kn+3kn+..+kkn=kn×2k2=O(nk)
两两合并
第 一 次 合 并 : 2 n k ∗ k 2 = n 第一次合并:2\frac{n}{k}*\frac{k}{2}=n 第一次合并:2kn∗2k=n
第 二 次 合 并 : 2 2 n k ∗ k 4 = n 第二次合并:2^2\frac{n}{k}*\frac{k}{4}=n 第二次合并:22kn∗4k=n
第 l o g k 次 合 并 : 2 l o g k n k ∗ k k = n 第logk次合并:2^{logk}\frac{n}{k}*\frac{k}{k}=n 第logk次合并:2logkkn∗kk=n
时 间 复 杂 度 : O ( n l o g k ) 时间复杂度:O(nlogk) 时间复杂度:O(nlogk)
优先队列,最小堆
遍 历 n 次 , 每 次 调 整 时 间 l o g k − > O ( n l o g k ) 遍历n次,每次调整时间logk->O(nlogk) 遍历n次,每次调整时间logk−>O(nlogk)
代码 -
合并K个排序链表
//方法1 逐一合并 O(nk)
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
// ListNode head=null;
// for(ListNode node:lists) {
// head=merge(head,node);
// }
// return head;
}
public ListNode merge(ListNode l1, ListNode l2) {
if(l1==null) return l2;
if(l2==null) return l1;
if(l1.val<l2.val) {
l1.next=merge(l1.next,l2);
return l1;
}
l2.next=merge(l1,l2.next);
return l2;
}
}
//方法2 两两合并O(nlogk)
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int len=lists.length;
if(len==0) return null;
while(len>1) {
for(int i=0; i<len/2; i++) {
lists[i]=merge(lists[2*i],lists[2*i+1]);
}
//如果lists总数是奇数个,则还剩一个
if(len%2==1) {
lists[len/2]=lists[len-1];
len=len/2+1;//规模减半+1
}else len=len/2;//规模减半
}
return lists[0];
}
public ListNode merge(ListNode l1, ListNode l2) {
if(l1==null) return l2;
if(l2==null) return l1;
if(l1.val<l2.val) {
l1.next=merge(l1.next,l2);
return l1;
}
l2.next=merge(l1,l2.next);
return l2;
}
}
//优先队列,小顶堆 O(nlogk)
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0) return null;
int k = lists.length;
PriorityQueue<ListNode> q = new PriorityQueue<>((l1,l2)->l1.val-l2.val);
for(int i=0; i<k; i++) {
if(lists[i]==null) continue;//因为没有说每个链表的长度
q.offer(lists[i]);
}
ListNode h = new ListNode(-1),cur=h;
while(q.size()>0){
ListNode node = q.poll();
cur.next = node;
cur=cur.next;
if(node.next!=null) {
q.offer(node.next);
}
}
return h.next;
}
- 合并k个数组,总元素为n个
//暴力,先合并,再排序 O(nlogn)
//逐一合并 O(nk)
//两两合并O(nlogk)
//不能使用优先队列,小顶堆,因为无法根据优先队列中的最小值获取其所在的数组及对应的下一个元素