Merge
k
sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
链表为降序,合并后也为降序。链表内不能变。
算法:
这里使用STL的priorit_queue,它是优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序,
每次的push和pop操作,队列都会动态的调整,以达到我们预期的方式来存储。例如:我们常用的操作就是对数据排序,优先队列默认的是数据大的优
先级高。所以我们无论按照什么顺序push一堆数,最终在队列里总是top出最大的元素,所以这里我们需要改成小顶堆。
该算法维护一个大小为k的堆,每次都会取堆顶的最小元素放到结果中,然后读取该元素的下一个元素(若为空,跳过)放入堆中,重新维护好。因为
每个链表是有序的,那么下次取得肯定是原链表的下一个元素(更小),每次又是取当前k个元素中最小的,所以当所有链表都读完时结束,这个时候所有元素按从小到大放在结果链表中。这个算法每个
元素要读取一次,即是k*n次,然后每次读取元素要把新元素插入堆中要logk的复杂度,所以总时间复杂度是O(nklogk)。空间复杂度是堆的大小,即为
O(k)。
code
class Solution {
public:
struct cmp
{
bool operator() (ListNode *p1,ListNode* p2)
{
return p1->val > p2->val; // 第一个元素大于第二个元素,返回真时; 对应的是小根堆,升序!
} // 当想要大根堆,降序时,让它返回false就好,即用'<' (默认值)
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*,vector<ListNode*>,cmp> pq;
for (int i = 0; i < lists.size(); ++i) {
if(lists[i]!=NULL){
pq.push(lists[i]);
}
}
ListNode* tmp;
ListNode* head = NULL;
ListNode* pre = NULL;
while(!pq.empty()){
tmp = pq.top();
pq.pop();
if(pre==NULL)
head = tmp;
else
pre->next = tmp;
pre = tmp;
tmp = tmp->next;
if(tmp!=NULL)
pq.push(tmp);
}
return head;
}
};