题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入: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
示例 2:
输入:lists = []
输出:[]
示例 3:
输入:lists = [[]]
输出:[]
法一:按顺序两两合并:
时间O(n)*k^2,空间O(1)
/**
* 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 {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.empty()) return nullptr;
int n = lists.size();
ListNode *res = lists[0];
for (int i = 1; i < n; ++i) {
res = mergeTwoLists(res, lists[i]);
}
return res;
}
ListNode* mergeTwoLists(ListNode *l1, ListNode *l2) {
ListNode *root = new ListNode(0), *pre = root;
while (l1 && l2) {
if (l1->val <= l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
pre->next = l1 ? l1 : l2;
pre=root->next;
delete root;
return pre;
}
};
法二:分治,两两合并,四四合并。。。:
空间O(logk)(递归栈),时间O(n*klogk)(因为分治是O(klogk),合并要O(n))
在这里插入代码片class Solution {
public:
// 合并两个有序链表
ListNode* merge(ListNode* p1, ListNode* p2){
if(!p1) return p2;
if(!p2) return p1;
if(p1->val <= p2->val){
p1->next = merge(p1->next, p2);
return p1;
}else{
p2->next = merge(p1, p2->next);
return p2;
}
}
ListNode* merge(vector<ListNode*>& lists, int start, int end){
if(start == end) return lists[start];
int mid = (start + end) / 2;
ListNode* l1 = merge(lists, start, mid);
ListNode* l2 = merge(lists, mid+1, end);
return merge(l1, l2);
}
/*
int interval = 1;
while (interval < len) {
// 根据当前间隔,两两合并,合并后的结果保存在两个链表的第一个
for (int i = 0; i < len - interval; i += 2 * interval) {
lists[i] = mergeTwoLists(lists[i], lists[i + interval]);
}
interval *= 2;
}
*/
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.size() == 0) return nullptr;
return merge(lists, 0, lists.size()-1);
}
};
法三:优先队列(堆,优先级高/低在堆顶,插删O(logk)):
时间O(kn*logk)(kn个元素),空间O(k)
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> pri_queue;
// 建立大小为k的小根堆
for(auto elem : lists){
if(elem) pri_queue.push(elem);
}
// 可以使用哑节点/哨兵节点
ListNode dummy(-1);
ListNode* p = &dummy;
// 开始出队
while(!pri_queue.empty()){
ListNode* top = pri_queue.top(); pri_queue.pop();
p->next = top; p = top;
if(top->next) pri_queue.push(top->next);
}
return dummy.next;
}
};
定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。
当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。