Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
这道题目在分布式系统中非常常见,来自不同client的sorted list要在central server上面merge起来。这个题目一般有两种做法,下面一一介绍并且分析复杂度。 第一种做法比较容易想到,就是有点类似于MergeSort的思路,就是分治法,不了解MergeSort的朋友,请参见 归并排序-维基百科 ,是一个比较经典的O(nlogn)的排序算法,还是比较重要的。思路是先分成两个子任务,然后递归求子任务,最后回溯回来。这个题目也是这样,先把k个list分成两半,然后继续划分,知道剩下两个list就合并起来,合并时会用到 Merge Two Sorted Lists 这道题。
我们来分析一下上述算法的时间复杂度。假设总共有k个list,每个list的最大长度是n,那么运行时间满足递推式T(k) = 2T(k/2)+O(n*k)。根据主定理,可以算出算法的总复杂度是O(nklogk)。如果不了解主定理的朋友,可以参见 主定理-维基百科 。空间复杂度的话是递归栈的大小O(logk)。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
if(lists.size()==0) return NULL;
return helper(lists,0,lists.size()-1);
}
ListNode *helper(vector<ListNode *> &lists,int s,int t){
if(s<t){
int m=(s+t)/2;
return merge(helper(lists,s,m),helper(lists,m+1,t));
}
else{
return lists[s];
}
}
ListNode *merge(ListNode *p1,ListNode *p2){
ListNode *dummy=new ListNode(-1);
ListNode *cur=dummy;
while(p1&&p2){
if(p1->val<p2->val){
cur->next=p1;
p1=p1->next;
cur=cur->next;
}
else{
cur->next=p2;
p2=p2->next;
cur=cur->next;
}
}
while(p1){
cur->next=p1;
p1=p1->next;
cur=cur->next;
}
while(p2){
cur->next=p2;
p2=p2->next;
cur=cur->next;
}
return dummy->next;
}
};
接下来我们来看第二种方法。这种方法用到了堆的数据结构,思路比较难想到,但是其实原理比较简单。维护一个大小为k的堆,每次去堆顶的最小元素放到结果中,然后读取该元素的下一个元素放入堆中,重新维护好。因为每个链表是有序的,每次又是去当前k个元素中最小的,所以当所有链表都读完时结束,这个时候所有元素按从小到大放在结果链表中。这个算法每个元素要读取一次,即是k*n次,然后每次读取元素要把新元素插入堆中要logk的复杂度,所以总时间复杂度是O(nklogk)。空间复杂度是堆的大小,即为O(k)。代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
struct cmp {
bool operator() (ListNode *a, ListNode *b) {
return a->val > b->val;
}
};
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
priority_queue<ListNode*,vector<ListNode*>,cmp> heap;
for(int i=0;i<lists.size();i++){
if(lists[i]!=NULL){
heap.push(lists[i]);
}
}
ListNode *head=NULL;
ListNode *prev=NULL;
ListNode *tmp;
while(!heap.empty()){
tmp=heap.top();
heap.pop();
if(prev==NULL){
head=tmp;
}
else{
prev->next=tmp;
}
prev=tmp;
if(tmp->next!=NULL){
heap.push(tmp->next);
}
}
return head;
}
};
http://zh.wikipedia.org/wiki/%E4%B8%BB%E5%AE%9A%E7%90%86