本文主要是介绍每日OJ题_链表④_力扣23. 合并 K 个升序链表(小根堆_归并),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
力扣23. 合并 K 个升序链表
解析代码1(小根堆优化)
解析代码2(递归_归并)
力扣23. 合并 K 个升序链表
23. 合并 K 个升序链表
难度 困难
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 = [[]] 输出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i]
按 升序 排列lists[i].length
的总和不超过10^4
/*** 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) {}
};
解析代码1(小根堆优化)
之前写过合并两个有序链表的题,此题暴力解法就是依次合并两个有序链表,合并K次。时间复杂度是O(N*K^2),是N^3级别的。
在暴力解法基础上可以使用小根堆优化,合并 K 个升序链表时,选择 K 个链表中,头结点值最小的那⼀个的插入到新链表,时间复杂度是O(N*K*logK)。下面是小根堆优化的代码:
/*** 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 {struct cmp{bool operator()(const ListNode* l1, const ListNode* l2){return l1->val > l2->val;}};public:ListNode* mergeKLists(vector<ListNode*>& lists) {priority_queue<ListNode*, vector<ListNode*>, cmp> heap;for(auto& e : lists) // 所有头结点进入小根堆{if(e)heap.push(e);}ListNode* newHead = new ListNode(0);ListNode* tmp = newHead;while(!heap.empty()){ // 尾插堆顶结点到新链表,再把旧链表下个结点插入小根堆ListNode* cur = heap.top();heap.pop();tmp->next = cur;tmp = cur;if(cur->next){heap.push(cur->next);}}tmp = newHead->next;delete newHead;return tmp;}
};
解析代码2(递归_归并)
- 递归出口:如果当前要合并的链表编号范围左右值相等,无需合并,直接返回当前链表。
- 应用二分思想,等额划分左右两段需要合并的链表,使这两段合并后的长度尽可能相等。
- 对左右两段分别递归,合并[left,right]范围内的链表。
- 最后调用合并两个链表函数进行合并。
/*** 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) {return merge(lists, 0, lists.size() - 1);}ListNode* merge(vector<ListNode*>& lists, int left, int right){if(left > right) // 区间不存在return nullptr;if(left == right) // 只有一个链表return lists[left];int mid = (left + right) >> 1;ListNode* list1 = merge(lists, left, mid);ListNode* list2 = merge(lists, mid+1, right);// 上面递归得到一个/两个链表return mergeTwoLists(list1, list2);}ListNode* mergeTwoLists(ListNode* list1, ListNode* list2){if(list1 == nullptr)return list2;if(list2 == nullptr)return list1;if(list1->val <= list2->val){list1->next = mergeTwoLists(list1->next, list2);return list1;}else{list2->next = mergeTwoLists(list2->next, list1);return list2;}}
};
这篇关于每日OJ题_链表④_力扣23. 合并 K 个升序链表(小根堆_归并)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!