Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
算法一:用multiset对节点排序,仅在第一次排序时花费O(k log(k))时间,后面每次更新一个节点费时 log(k)。时间复杂度O(n log(k)),n为所有节点数。 但测试效果不是很理想。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class comp{
public:
bool operator()(ListNode *p, ListNode *q){ return p->val < q->val; }
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode *head=NULL, *cur=head;
multiset<ListNode*,comp> table;
for(int i=0;i<lists.size();i++){
if(lists[i]) table.insert(lists[i]);
}
ListNode *q;
while(!table.empty()){
multiset<ListNode*,comp>::iterator it = table.begin();
if(head==NULL){
head = *it; cur = head;
q = (*it)->next;
table.erase(it);
if(q) table.insert(q);
}
else{
cur->next = *it; cur = cur->next;
ListNode *q = (*it)->next;
table.erase(it); //cost log(k) time to erase the old node
if(q) table.insert(q); //add the next node, cost log(k) time to re-sort the node
}
}
if(cur) cur->next = NULL;
return head;
}
};
算法二:multiset是用红黑树实现的,其实用堆就够了。priority_queue用堆实现,但效率并没有提高多少。数据结构上已无法再改进,只能从算法上改进。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class comp{
public:
bool operator()(ListNode *p, ListNode *q){ return p->val > q->val; }
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode *head=NULL, *cur=head;
priority_queue<ListNode*,vector<ListNode*>,comp> table;
for(int i=0;i<lists.size();i++){
if(lists[i]) table.push(lists[i]);
}
ListNode *q;
while(!table.empty()){
q = table.top();
table.pop();
if(head==NULL){
head = q; cur = head;
}
else{
cur->next = q; cur = cur->next;
}
q = q->next;
if(q) table.push(q); //add the next node, cost log(n) time to re-sort the node
}
if(cur) cur->next = NULL;
return head;
}
};
算法三: 用分治思想。 但从AC通过时间来看似乎仍然没有提高什么效率。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class comp{
public:
bool operator()(ListNode *p, ListNode *q){ return p->val > q->val; }
};
class Solution {
public:
ListNode* merge2Lists(ListNode* L1, ListNode* L2){
if(L1==NULL) return L2;
else if(L2==NULL) return L1;
ListNode *head = NULL, *cur = head;
if(L1->val <= L2->val){ head = cur = L1; L1 = L1->next; }
else{ head = cur = L2; L2 = L2->next; }
while(L1 && L2){
if(L1->val <= L2->val){ cur->next = L1; cur = cur->next; L1 = L1->next; }
else{ cur->next = L2; cur = cur->next; L2 = L2->next; }
}
if(L1) cur->next = L1;
else cur->next = L2;
return head;
}
ListNode* mergeKLists(vector<ListNode*>& lists,int p,int r) {
if(p>r) return NULL;
if(p==r) return lists[p];
if(p==r-1) return merge2Lists(lists[p],lists[r]);
ListNode *L1 = mergeKLists(lists,p,(p+r)/2);
ListNode *L2 = mergeKLists(lists,(p+r)/2 + 1, r);
return merge2Lists(L1,L2);
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.empty()) return NULL;
return mergeKLists(lists,0,lists.size()-1);
}
};
PS: 在AC time统计图看到三个算法时间都挺靠后的。但理论上来讲时间复杂度下限应该是O(n log(k)),再将别人的AC代码测试发现效果相差不大,都在400ms左右,但统计表上显示有50ms 的C++测试,似乎还有更好的算法???或者是后面又增加了测试用例??