与之前的题目类似:
leetcode-21 合并两个有序链表
这是一个多条有序链表,然后不断去选择查询,然后定义一个新的节点,把链表接入进去,唯一刚开始觉得不好做的情况是,多条链表不好操作,判断大小也麻烦。
之前写:two sum,three sum,four sum这一种题目的时候,我很希望能找一个通法去解决,但是就找不到。
这题的思路我能想到,但是边界一直处理不了。
题目分析如下:
(1)和合并两条有序链表的方式一样,找到头结点的每一个最小是,之后寻找下一个头节点。
(2)那么如何去找一个序列中的最小值呢?当然是优先队列,其实就是堆,请参考《算法笔记》335页,这里需要去定义一个小根堆,通常我们定义的方式是这样的:
这里参入一个连接介绍一下小根堆的写法:STL-priority_queue用法(重点: 升序,小根堆)
priority_queue<int,vector<int>,greater<int>>
顺便提一下:定义大根堆的方法:
priority_queue<int,vector<int>,less<int>>
堆的查找是O(1)复杂度,但是插入的一个数是O(log n)的负载度,如果这里和循环对比,可能好多了。
(3)之后就是多路归并的情况了,如果找到值,插入链表之后,就要把当前节点的最后一个值送到堆里面,之后小根堆会管这件事。
代码如下:
/**
* 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) {
这很像是多路归并排序的感觉,但是需要去使用链式去表达出来
struct cmp{
bool operator() (ListNode* a,ListNode* b){
return a->val>b->val;
}
};
//定义一个大顶堆
priority_queue<ListNode*,vector<ListNode*>,cmp> heap;
auto dummy=new ListNode(-1),tail=dummy;
//如果存在k个序列,然后k个序列去排序连接,同样是可以得到答案
//前k个点取出最小值,方式有很多,优先队列可以。
//优先队列是大根堆,虽然可以去使用greater去使用
//现在的操作是,先把k个链表的头节点插入堆里面去。然后选出一个最小的数
//如果是非空,才可以去进行插入
for(auto nums:lists) if(nums) heap.push(nums);
//然后就开始去进行k路归并,在堆里面找出最小的值
//当堆里面存在元素,取出头结点的元素,然后插入当tail的尾部后面
while(heap.size()){
auto t=heap.top();
heap.pop();
tail=tail->next=t;//插入完成之后,t成为了新的为节点,还是需要去跟新一下
//如果下一个节点存在元素的话,那么将t的下一个节点插入,其实堆就是维护了一段长度的列队
if(t->next) heap.push(t->next);
}
//如果存在最后一条链表,然后再去插入一下
return dummy->next;
}
};