23. 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解法1
给定k个有序链表,合并为一个链表返回;
新建链表指针,逐一对每个链表进行合并,便利全局后返回;
复杂度O(N*k^2);
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* res=nullptr; //初始化习惯
for(int i=0;i<lists.size();i++)
res=MergetwoList(res,lists[i]);
return res;
}
private:
ListNode* MergetwoList(ListNode * a, ListNode *b){
ListNode head; //创建一个对象,包含空间
ListNode *tail=&head; //创建指针需要new空间
ListNode * PtrA=a,*PtrB=b;
if ((!a) || (!b)) return a ? a : b; //一方为空,返回另一方
while(PtrA&&PtrB)
{
if(PtrA->val<PtrB->val)
{
tail->next=PtrA;
PtrA=PtrA->next;
}
else
{
tail->next=PtrB;
PtrB=PtrB->next;
}
tail=tail->next;
}
tail->next=PtrA? PtrA:PtrB; //一方为空,后接另一方
return head.next;
}
};
164 ms 10.1 MB
解法2
分治策略;
两两合并,最后合并为一个;
复杂度为O(logn);
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
return Merge(lists,0,lists.size()-1);
}
private:
ListNode* Merge(vector<ListNode*>& lists,int l, int r)
{
if(l==r) return lists[l];
if(l>r) return nullptr;
int mid=l+(r-l)/2;
return MergetwoList(Merge(lists,l,mid),Merge(lists,mid+1,r));
}
ListNode* MergetwoList(ListNode * a, ListNode *b){
ListNode head; //创建一个对象,包含空间
ListNode *tail=&head; //创建指针需要new空间
ListNode * PtrA=a,*PtrB=b;
if ((!a) || (!b)) return a ? a : b; //一方为空,返回另一方
while(PtrA&&PtrB){
if(PtrA->val<PtrB->val){
tail->next=PtrA;
PtrA=PtrA->next;
}else{
tail->next=PtrB;
PtrB=PtrB->next;
}
tail=tail->next;
}
tail->next=PtrA? PtrA:PtrB; //一方为空,后接另一方
return head.next;
}
};
24 ms 9.9 MB
注意点
Merge函数中递归返回mergetwolist执行后的头指针,省去创建多余变量保存头指针;
解法3
优先队列(最小堆)保存每个头节点,最小值出队,出队的节点的next入队;
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
for(auto node:lists)
{
if(node) q.push({node->val,node});
}
ListNode head;
ListNode *tail=&head;
while(!q.empty())
{
tail->next=q.top().ptr; //优先队列只有top,没有front
tail=tail->next;
if (q.top().ptr->next) q.push({q.top().ptr->next->val,q.top().ptr->next});
q.pop();
}
return head.next; //head对象内容改为head.next
}
private:
struct Status {
int val;
ListNode *ptr;
bool operator <(const Status &rhs) const{
return val>rhs.val; //优先队列,反向排序
}
};
priority_queue<Status> q;
};
48 ms 10.5 MB
注意点
1.创建优先队列
priority_queue<Status> q;
需要先重载Status的<号,因为listnode无法重载,故新建结构Status,存放listnode和其值,<号重载将大的放前面,如此优先队列会将小的放最前;
2.优先队列只有 top()成员变量,无front;
3.对象的成员调用为 .val,对象指针的成员调用为->val;
4.新建listnode指针时需先新建listnode对象,建立空间让指针指向,调用head时返回head.next;