将每个list的最小节点放入一个priority queue (min heap)中。之后每从queue中取出一个节点,则将该节点在其list中的下一个节点插入,以此类推直到全部节点都经过priority queue。由于priority queue的大小为始终为k,而每次插入的复杂度是log k,一共插入过nk个节点。时间复杂度为O(nk logk),空间复杂度为O(k)。
注意C++的STL中的priority queue默认是max heap,定义一个新的比较函数。
注意C++的STL中的priority queue默认是max heap,定义一个新的比较函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Solution { public: struct compNode { bool operator()(ListNode *p, ListNode *q) const { return p->val>q->val; } }; ListNode *mergeKLists(vector<ListNode *> &lists) { priority_queue<ListNode*, vector<ListNode*>, compNode> pq; ListNode *dummy = new ListNode(0), *tail = dummy; for(int i=0; i<lists.size(); i++) if(lists[i]) pq.push(lists[i]); while(!pq.empty()) { tail->next = pq.top(); tail = tail->next; pq.pop(); if(tail->next) pq.push(tail->next); } return dummy->next; } }; |
利用合并两个list的方法,依次将每个list合并到结果的list中。这个方法的空间复杂度为O(1),时间复杂度为:
2n + 3n + ... + kn = [(k+1)*k/2-1]*n = O(nk^2)
由于时间复杂度较大,大数据测试会超时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | class Solution { public: ListNode *mergeKLists(vector<ListNode *> &lists) { ListNode *ret = NULL; for(int i=0; i<lists.size(); i++) ret = merge2Lists(ret, lists[i]); return ret; } ListNode* merge2Lists(ListNode *h1, ListNode *h2) { ListNode *dummy = new ListNode(0), *tail = dummy; while(h1 && h2) { if(h1->val<=h2->val) { tail->next = h1; h1 = h1->next; } else { tail->next = h2; h2 = h2->next; } tail = tail->next; } tail->next = h1 ? h1 : h2; return dummy->next; } }; |
类似merge sort,每次将所有的list两两之间合并,直到所有list合并成一个。如果用迭代而非递归,则空间复杂度为O(1)。时间复杂度:
2n * k/2 + 4n * k/4 + ... + (2^x)n * k/(2^x) = nk * x
k/(2^x) = 1 -> 2^x = k -> x = log2(k)
所以时间复杂度为O(nk log(k)),与方法一相同。
2n * k/2 + 4n * k/4 + ... + (2^x)n * k/(2^x) = nk * x
k/(2^x) = 1 -> 2^x = k -> x = log2(k)
所以时间复杂度为O(nk log(k)),与方法一相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class Solution { public: ListNode *mergeKLists(vector<ListNode *> &lists) { if(lists.empty()) return NULL; int end = lists.size()-1; while(end>0) { int begin = 0; while(begin<end) { lists[begin] = merge2Lists(lists[begin], lists[end]); begin++; end--; } } return lists[0]; } ListNode* merge2Lists(ListNode *h1, ListNode *h2) { ListNode *dummy = new ListNode(0), *tail = dummy; while(h1 && h2) { if(h1->val<=h2->val) { tail->next = h1; h1 = h1->next; } else { tail->next = h2; h2 = h2->next; } tail = tail->next; } tail->next = h1 ? h1 : h2; return dummy->next; } }; |
我的思路是:
ReplyDelete直接把所有节点push进一个vector,然后sort一下,重新串起来就好了,时间复杂度为O(nk log(nk)),也能过。
这种解法虽然能过,但空间复杂度太大,并不是效率高的做法。
Deletepython 2分法遭遇了最大递归深度的问题,而实际case最快的算法就是重新sort,理论上应该更慢,却快那么多
Delete