题目链接:https://leetcode.com/problems/merge-k-sorted-lists/
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
思路:刚开始想要两两合并,但是超时了,后来看到用优先队列来做会降低很多时间复杂度。我看到很多人分析时间复杂度有很多错误,那么我们先来分析一下这两种做法的时间复杂度。
首先是两两合并,这种方法的思路比较简单,两个合并之后再和后来的合并,其时间复杂度分析如下,第一个列是行号,第二列是一个链表的元素个数,第三列是合并用的时间:
1 n 0
2 n n+n
3 n 2*n+n //因为此时前面链表合并过之后的长度变为2*n
4 n 3*n+n //前面合并的链表长度变为3*n
5 n 4*n+n
.....
k n (k-1)*n+n
因此可以得出总的运行时间为:
2*n+3*n+4*n+...+k*n
= n * ( k * (k+1)/2 - 1 )
= n*(k * k/2 + k * 2 - 1)
= n*k*k/2 + n*k*2 - n
因此可以得出两两合并时间复杂度为O(n*k*k)。
然后再来分析一下用优先队列的思路和时间复杂度。
这种方式的思路是将k个链表放到小顶堆组成的优先队列中。每次取出顶部元素,时间复杂度是O(1),取出顶部元素之后再将其后的元素插入到堆中。
这样最终就可以将所有元素取出。时间复杂分析如下:
总共会有n*k个元素,每个元素都会插入和删除到优先队列中,因为优先队列的长度是k,即链表的个数,因此插入删除时间复杂度都是O(log(k)),这样总的时间复杂度将为O(n*k*log(k)).
优先队列代码如下:/**
* 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) {
auto cmp = [](ListNode* a, ListNode* b) { return a->val > b->val; };
priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> que(cmp);
ListNode *pHead = new ListNode(0), *p = pHead;
for(auto val: lists) if(val) que.push(val);
while(!que.empty())
{
auto val = que.top();
p->next = val, p = p->next;
que.pop();
if(val->next) que.push(val->next);
}
p = pHead->next;
delete pHead;
return p;
}
};
参考:http://bangbingsyb.blogspot.com/2014/11/leetcode-merge-k-sorted-lists.html