问题是将k个排序列表合并到一个排序列表。 我已经完成了三种解决方案。 首先是二分法,如下:
ListNode* mergeKLists(vector<ListNode*>& lists)
{
if(lists.size()==0) return NULL;
return mergeKLists(lists,0,lists.size()-1);
}
ListNode* mergeKLists(vector<ListNode*>& lists,int start,int end)
{
if(start==end) return lists[start];
ListNode *l1=mergeKLists(lists,start,(start+end)/2);
ListNode *l2=mergeKLists(lists,(start+end)/2+1,end);
return merge2Lists(l1,l2);
}
复杂度约为O(nklogk)=(2n k / 2 + 4n k / 4 + ..... nk * k / k)
其次,使用堆,如下所示:
static bool heapComp(ListNode* a, ListNode* b) {
return a->val > b->val;
}
ListNode* mergeKLists(vector<ListNode*>& lists) { //make_heap
ListNode head(0);
ListNode *curNode = &head;
vector<ListNode*> v;
for(int i =0; i<lists.size(); i++){
if(lists[i]) v.push_back(lists[i]);
}
make_heap(v.begin(), v.end(), heapComp); //vector -> heap data strcture
while(v.size()>0){
curNode->next=v.front();
pop_heap(v.begin(), v.end(), heapComp);
v.pop_back();
curNode = curNode->next;
if(curNode->next) {
v.push_back(curNode->next);
push_heap(v.begin(), v.end(), heapComp);
}
}
return head.next;
}
复杂性大约是O(nklogk),因为精炼堆需要logk,我们需要这样做nk次。
第三种方法是我很困惑的。我采用Haffman Three的想法,每次我拿两个最短的列表并进行合并,如下:
struct Node{
ListNode* node;
int length;
Node(ListNode *n,int x){
node=n;
length=x;
}
};
bool compare(Node l1,Node l2)
{
return l1.length>l2.length;
}
ListNode* mergeKLists(vector<ListNode*>& lists)
{
vector<Node> newlists;
if(lists.empty()) return NULL;
for(int i=0;i<lists.size();i++)
newlists.push_back(Node(lists[i],length(lists[i])));
make_heap(newlists.begin(),newlists.end(),compare);
while(newlists.size()!=1)
{
Node p=newlists.front();
pop_heap (newlists.begin(),newlists.end(),compare);
Node q=newlists.front();
newlists.pop_back();
pop_heap (newlists.begin(),newlists.end(),compare);
newlists.pop_back();
newlists.push_back(Node(merge2Lists(p.node,q.node),p.length+q.length));
push_heap (newlists.begin(),newlists.end(),compare);
}
return newlists[0].node;
}
我认为复杂性是关于O(nklogk + klogk),因为与第一种方法相比,它需要额外的pop_heap O(klogk)。
但是,如果k列表的长度变化很大。很明显,第三种方法优于第一种方法。例如,长度为(20,50,40)的列表,第一个需要进行20 + 50 + 70 + 40 = 180比较,而第三个只需要20 + 40 + 60 + 50 = 170个比较。
这是矛盾吗?
我是否正确计算这些方法的复杂性?
如果列表的长度变化很大,有人能解释这些方法的复杂性吗?