/*Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. */ #include <iostream> #include<algorithm> #include<stdio.h> #include<queue> #include<vector> using namespace std; struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} };
//struct cmp:public binary_function<ListNode*,ListNode*,bool> class cmp//class is more simple than struct { public: bool operator()(ListNode* la,ListNode* lb) { if(!la||!lb) return !la; return la->val>lb->val; } };
class Solution2 { ListNode* mergeKLists(vector<ListNode*>& lists) { //Time LimitExceeded if(lists.empty()) return NULL; ListNode*head=NULL,*pos=NULL; do { make_heap(lists.begin(),lists.end(),cmp()); pop_heap(lists.begin(),lists.end(),cmp()); ListNode* last=lists.back(); if(head==NULL) { head=last; pos=last; } else { pos->next=last; pos=last; } if(last==NULL) break; lists.pop_back(); lists.push_back(last->next); } while(1); return head; } };
class Solution1 { public: ListNode* mergeKLists(vector<ListNode*>& lists) { for(vector<ListNode*>::iterator it=lists.begin(); it!=lists.end();) if(*it==NULL) it=lists.erase(it); else it++; if(lists.empty()) return NULL; ListNode*head=NULL,*pos=NULL,*last=NULL; make_heap(lists.begin(),lists.end(),cmp()); do { pop_heap(lists.begin(),lists.end(),cmp()); last=lists.back(); if(head==NULL) { head=last; pos=last; } else { pos->next=last; pos=last; } lists.erase(lists.end()-1); if(last->next) { lists.push_back(last->next); push_heap(lists.begin(),lists.end(),cmp()); } } while(lists.size()); if(pos!=NULL) pos->next=NULL; return head; } };
class Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { vector<int>::size_type i; priority_queue<ListNode*,vector<ListNode*>,cmp>Q; for(i=0; i<lists.size(); i++) { if(lists[i]!=NULL) Q.push(lists[i]); } ListNode*head=NULL,*pos=NULL,*pre=NULL; while(!Q.empty()) { pre=Q.top(); Q.pop(); if(head==NULL) { head=pre; pos=pre; } else { pos->next=pre; pos=pre; } if(pre->next) Q.push(pre->next); } return head; } };
int main() { ListNode* ls[8]; for(int i=0; i<5; i++) ls[i] =new ListNode(4-i); ls[5]=new ListNode(3); ls[5]->next=NULL; ls[6]=NULL; ls[7]=NULL; vector<ListNode*> lists(ls,ls+8); //Solution s; Solution1 s; ListNode*head=s.mergeKLists(lists); while(head) { cout<<head->val<<endl; head=head->next; } return 0; }
首先用常规的合并方法肯定是会超时的。我们现在使用堆排序来做。
Solution2和Solution1最大的区别就是make_heap放在了循环里面,这也是我参考网上其他网友的答案。但是Solution2超时,而Solution1能AC。其实道理很简单,我们知道k个元素建堆的时间复杂度是O(k),而调整堆(pop_head和push_head)的复杂度是O(lgk)。若是把make_heap放在循环里面,那么每次都会重新建堆。而其实我们只是对换了堆顶元素和最后一个元素,所以仅仅需要调整堆就可以。综述,Solution2因为一个简单的操作把总的时间复杂度变为了O(nk),而Solution1的时间复杂度仅仅是O(nlgk)。
Solution其实就是运用了priority_queue,而优先队列本来就是使用了堆的相关操作,所以和Solution1的本质相同。
原文:http://www.cnblogs.com/heqinghui/p/4840692.html