leetcode:23. 合并K个升序链表
题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
输入:lists = []
输出:[]
输入:lists = [[]]
输出:[]
解答 & 代码
解法一:小根堆(优先队列实现)
每次合并,都应该选择当前各个链表剩余部分最前面的节点的值的大小,选择值最小的节点插入。
问题就在于如何得到值最小的节点?可以用小根堆来存储各个链表剩余部分最前面的节点。
优先队列
priority_queue
:
- 头文件:
#include <queue>
- 定义:
priority_queue<Type, Container, Functional>
- 大根堆:
priority_queue<int> maxHeap
orpriority_queue<int, vector<int>, less<int>> maxHeap
- 小根堆:
priority_queue<int, vector<int>, greater<int>> minHeap
- 自定义类型:如下面代码所示
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
private:
// 小根堆的回调函数
struct cmp {
bool operator() (ListNode* node1, ListNode* node2) {
return node1->val > node2->val;
}
};
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
// 小根堆(基于优先队列)
priority_queue<ListNode*, vector<ListNode*>, cmp> minHeap;
// 初始将每个链表的头节点(如果不为空)存入小根堆
for(int i = 0; i < lists.size(); ++i)
{
if(lists[i] != nullptr)
minHeap.push(lists[i]);
}
ListNode* dummyHead = new ListNode();
ListNode* pre = dummyHead;
while(!minHeap.empty())
{
ListNode* minNode = minHeap.top();
minHeap.pop();
pre->next = minNode;
pre = pre->next;
if(minNode->next != nullptr)
minHeap.push(minNode->next);
}
return dummyHead->next;
}
};
复杂度分析:设一共 K 个链表,这 K 个链表节点总数为 N
- 时间复杂度 O(N × logK):优先队列中元素不超过 K 个,因此插入和删除时间代价为 O(logK),N 个节点都会插入优先队列并删除一次
- 空间复杂度 O(K):优先队列中的元素不超过 K 个
执行结果:
执行结果:通过
执行用时:20 ms, 在所有 C++ 提交中击败了 79.35% 的用户
内存消耗:12.9 MB, 在所有 C++ 提交中击败了 74.70% 的用户