题目链接:23.合并K个排序链表
题解:
由二路归并变为k路归并,有优化的地方的!
题目简述:
k个有序链表,合并生成一个有序链表。
题解一:低效率(我的)
嗯,暴力去扫描每个最小值!
具体:
mint
:记录当前最小的节点。
minv
:记录当前最小节点所在的链表的下标
- 特判一下当前链表是否为空,是的话直接跳过。
- 如果能找到最小值,即
minv != -1
,则更新当前链表即最小值所在链表!
- 找不到最小值直接退出
时间复杂度:假设链表数组个数为 N,扫描每个最小值都要N次,所有链表元素为M的话,最终时间复杂度为 O(N*M)
欢迎查看题解二:使用堆优化!
AC代码一:
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) { auto dummy = new ListNode(-1), p = dummy; while(1){ auto mint = new ListNode(INT_MAX); int minv = -1; for(int i = 0; i < lists.size(); i++){ if(!lists[i]) continue; if(mint->val > lists[i]->val){ mint = lists[i]; minv = i; } } if(minv != -1) { p->next = mint; p = p->next; lists[minv] = lists[minv]->next; } else break; } return dummy->next; } };
|
题解二:高效率(别人的)
查找最小值可以使用堆来进行优化,将查询的时间复杂度从O(N)降到O(logN),整体时间复杂度为O(M*logN)
堆,即使用优先队列priority_queue
:
- 先将每个序列的头结点插入堆,(如果存在)
- 然后去取堆顶元素,直到去完(即最小值都已查找了一遍),若当前最小值有后继结点,则将其插入堆中。
由于使用的是priority_queue<ListNode*>
类型,所以需要重载小括号:
return a->val < b->val
:即默认的降序
return a->val > b->val
:即升序
特殊之处:priority_queue
的排序函数不是函数,是一个结构体,需要这样来写:
1 2 3 4 5
| struct Cmp{ bool operator() (ListNode* a, ListNode* b){ return a->val > b->val; } };
|
AC代码二:
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
|
class Solution { public: struct Cmp{ bool operator() (ListNode* a, ListNode* b){ return a->val > b->val; } }; ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*, vector<ListNode*>, Cmp> heap; auto dummy = new ListNode(-1), p = dummy; for(auto l : lists) if(l) heap.push(l); while(heap.size()){ auto t = heap.top(); heap.pop();
p->next = t; p = p->next; if(t->next) heap.push(t->next); } return dummy->next; } };
|