/*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; }
首先用常規的合併方法確定是會超時的。咱們如今使用堆排序來作。ios
Solution2和Solution1最大的區別就是make_heap放在了循環裏面,這也是我參考網上其餘網友的答案。可是Solution2超時,而Solution1能AC。其實道理很簡單,咱們知道k個元素建堆的時間複雜度是O(k),而調整堆(pop_head和push_head)的複雜度是O(lgk)。如果把make_heap放在循環裏面,那麼每次都會從新建堆。而其實咱們只是對換了堆頂元素和最後一個元素,因此僅僅須要調整堆就能夠。綜述,Solution2由於一個簡單的操做把總的時間複雜度變爲了O(nk),而Solution1的時間複雜度僅僅是O(nlgk)。spa
Solution其實就是運用了priority_queue,而優先隊列原本就是使用了堆的相關操做,因此和Solution1的本質相同。code