给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 = [[]]
输出:[]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路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) {
ListNode* res = nullptr;
if(lists.size() == 0)
return res;
return MergeSort(lists,0,lists.size() - 1);
}
//归并算法 将链表个数不断的分到只有两个两个合并
ListNode* MergeSort(vector<ListNode*>& lists,int left,int right)
{
if(left == right)
return lists[left];
int mid = (left + right) >> 1;
ListNode*temp_left = MergeSort(lists,left,mid);
ListNode* temp_right = MergeSort(lists,mid + 1,right);
ListNode* res = merge(temp_left,temp_right);
return res;
}
//合并两个有序链表
ListNode* merge(ListNode* l1,ListNode* l2)
{
ListNode* dummyHead = new ListNode(-1);
ListNode* cur = dummyHead;
while(l1 != nullptr && l2 != nullptr)
{
if(l1->val <= l2->val)
{
cur->next = l1;
l1 = l1->next;
}
else
{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
if(l1)
cur->next = l1;
if(l2)
cur->next = l2;
return dummyHead->next;
}
};
时间复杂度: k为链表的组数。
O(kn×log k)
思路二:使用堆实现。我们可以构建一个小顶堆,存储链表节点,将每个链表的第一个节点都加入该堆,然后再取出堆顶,取出堆顶之后将该链表的下一节点加入堆中,重复这一过程直到堆为空。
代码实现:
/**
* 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:
struct
{
bool operator()(ListNode* a,ListNode* b)
{
return a->val > b->val;
}
}cmp;
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.size() == 0)
return nullptr;
priority_queue<ListNode*,vector<ListNode*>,decltype(cmp)> temp;
//建立大小为k的小根堆
for(auto elem : lists)
{
if(elem)
temp.push(elem);
}
//使用哑结点
ListNode* dummyHead = new ListNode(-1);
ListNode* cur = dummyHead;
//如果链表组有k个那么 堆的大小也为k个
//开始出队
while(!temp.empty())
{
ListNode* top = temp.top();//取出最小的数值
temp.pop();
cur->next = top;//将链表链接上
cur = top;//转至下一节点
if(top->next)
{
temp.push(top->next);//取出当前组链表的下一个节点加入堆
}
}
return dummyHead->next;
}
};