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
Title Link: https://leetcode-cn.com/problems/merge-k-sorted-lists/
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).
/** * 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; } };
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).
/** * 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; } };
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.
Code source: https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/23-he-bing-kge-pai-xu-lian-biao-yi-bu-bu-you-hua-d/
/** * 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())); //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) { 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; } };