23. Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
题目链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/
思路
很容易想到的有2种方法:
1.所有元素逐个压入优先队列,再逐个输出。
2.所有vector两两合并。
下面对两个方法逐个分析。
法一:优先队列
运行结果:结果正确但超时。
仔细分析:链表是有序的,所以链表的头节点的大小代表了整个链表的最小值,因此如果后面的链都小于前面的链,那么队列就需要频繁调整。
改进:先插入所有头节点,取出时判断被取节点后面是否还有节点,有则继续入队。这样可以保证每次优先对头节点最小的链表进行整理,维护的队列大小从n减小到k,从而运行速度也减小。
时间复杂度O(nlogk),空间复杂度O(k)。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
struct cmp{
bool operator()(ListNode* n1, ListNode* n2){
return n1->val > n2->val;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.size()<=0) return NULL;
if(lists.size()==1) return lists[0];
priority_queue<ListNode* ,vector<ListNode*> , cmp> pq;
for(int i=0; i<lists.size(); ++i){
ListNode* head = lists[i];
if(head) pq.push(head);
}
ListNode* node = new ListNode(INT_MIN);
auto idx = node;
while(!pq.empty()){
auto top = pq.top();
idx->next = top;
idx = idx->next;
pq.pop();
if(top->next) pq.push(top->next);
}
return node->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) {
if(lists.size()<=0) return NULL;
if(lists.size()==1) return lists[0];
ListNode* node = new ListNode(0);
auto head1 = lists[0];
node->next = head1;
for(int i=1; i<lists.size(); ++i){
head1 = node;
auto head2 = lists[i];
while(head1->next && head2){
if(head1->next->val > head2->val){
auto tmp = head1->next;
head1->next = head2;
head2 = head2->next;
head1 = head1->next;
head1->next = tmp;
}else head1 = head1->next;
}
if(head2) head1->next = head2;
}
return node->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) {
int size = lists.size();
if (size == 0) {
return nullptr;
}
if (size == 1) {
return lists[0];
}
queue<ListNode*> waiting(deque<ListNode*>(lists.begin(), lists.end())); //将vector转为队列
//如果队列元素大于1,则取出两个进行合并,合并后的链表继续添加到链表尾部
while (waiting.size() > 1) {
ListNode *l1 = waiting.front();
waiting.pop();
ListNode *l2 = waiting.front();
waiting.pop();
waiting.push(merge2(l1, l2));
}
return waiting.front();
}
ListNode* merge2(ListNode *l1, ListNode *l2) {
ListNode *head = new ListNode(0);
ListNode *p = head;
while (l1 && l2) {
if (l1->val < l2->val) {
p->next = l1;
l1 = l1->next;
} else {
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
p->next = l1 ? l1 : l2;
return head->next;
}
};