# [leetcode][hard]23. Merge k Sorted Lists

Posted by kasitzboym on Tue, 18 Feb 2020 07:13:12 +0100

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```

## thinking

There are two easy ways to think of:

1. All elements are pushed into the priority queue one by one, and then output one by one.

2. Merge all vector s.

The following two methods are analyzed one by one.

### Method 1: priority queue

Run result: the result is correct but timed out.

Careful analysis: the linked list is ordered, so the size of the head node of the linked list represents the minimum value of the whole linked list. Therefore, if the chain behind is smaller than the chain ahead, the queue needs to be adjusted frequently.

Improvement: insert all header nodes first, judge whether there are nodes after the node to be fetched when fetching, and continue to join the queue if there are any. In this way, it can ensure that every time the smallest linked list of the head node is sorted out first, and the maintenance queue size is reduced from n to k, so the running speed is also reduced.

Time complexity O(nlogk), space complexity O(k).

```/**
* 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* 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;
}
};```

### Law 2: merger of two

The first list is taken as the basic list, and the latter one is continuously inserted in.

Disadvantages: when the size of the elements in each linked list is very uniform, the length of the linked list is longer and longer, and the insertion time is longer and longer (the elements will be traversed repeatedly).

```/**
* 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);
for(int i=1; i<lists.size(); ++i){
}
}
return node->next;
}
};```

Optimization: in terms of implementation logic, the two links are merged, and then the two links are continuously merged upward. It can be realized through linked list queue.

```/**
* 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())); //Turn vector into queue
//If the queue element is greater than 1, take out two to merge, and the merged linked list will continue to be added to the end of the linked list
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) {
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;