1. 题目来源
链接:23. 合并K个升序链表
2. 题目解析
前导题
k
路归并同二路归并一样。但是 k
路归并能处理的数据量更大。在本题中 k
个链表就拿 k
各指针分别指向头指针,每次比较 k
个指针的数值大小,取最小的一个即可。显然,可以拿堆来维护这个最小值,拿堆来维护这 k
个指针,取最小值是
O
(
1
)
O(1)
O(1) 的,然后将最小值的下一个元素插入到堆中是
O
(
l
o
g
k
)
O(logk)
O(logk) 的,所以总的时间复杂度就是
O
(
n
l
o
g
k
)
O(nlogk)
O(nlogk)。
注意:
- 需要自定义一个堆的比较函数,和
sort
自定义的比较函数不同
容器需要传入的不是比较函数,而是一个结构体,然后里面重载()
。 - 且优先队列默认为大根堆,写为
a->val > b->val
就为小根堆
容器在比较的时候会调用Cmp(a, b)
如果a
应该排到b
的前面,就返回true
否则返回false
,但由于优先队列默认大根堆,则需要反转一下,需要特别注意"<"
为从大到小排列,">"
为从小到大排列。 - 这篇博文不错:重载比较函数 的用法
- 原理的讲解:【速记】C++ STL自定义排序
- 时间复杂度: O ( n l o g k ) O(nlogk) O(nlogk)。
- 空间复杂度: O ( k ) O(k) O(k)
代码:
class Solution {
public:
struct Cmp {
bool operator() (ListNode* a, ListNode* b) {
return a->val > b->val;
}
};
priority_queue<ListNode*, vector<ListNode*>, Cmp> heap;
ListNode* mergeKLists(vector<ListNode*>& lists) {
auto dummy = new ListNode(-1), tail = dummy;
for (auto e:lists) if (e) heap.push(e); // 插入k个头结点
while (heap.size()) { // k路归并
auto t = heap.top(); // 堆顶为最小值
heap.pop();
tail = tail->next = t;
if (t->next) heap.push(t->next); // 指针向后移动一位
}
return dummy->next;
}
};