23. Merge k Sorted Lists - cocoder39/coco39_LC GitHub Wiki
Notes 2022
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
queue = []
for head in lists:
if head:
heapq.heappush(queue, (head.val, id(head), head)) # pq looks at the next value in the tuple (in this case, id), and sort based on that value. Suppose there is no id and there is tie in terms of first element in tuple, pq will try to compare the 3rd element ListNode, which is however not comparable.
mergedList = ListNode()
cur = mergedList
while queue:
_, _, node = heapq.heappop(queue)
cur.next = node
cur = node
if node.next:
heapq.heappush(queue, (node.next.val, id(node.next), node.next))
return mergedList.next
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
if not lists:
return None
mid = len(lists) // 2
if mid == 0:
return lists[0]
left, right = self.mergeKLists(lists[:mid]), self.mergeKLists(lists[mid:])
return self.merge2Lists(left, right)
def merge2Lists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
head = ListNode()
cur = head
while list1 is not None and list2 is not None:
if list1.val < list2.val:
cur.next = list1
list1 = list1.next
else:
cur.next = list2
list2 = list2.next
cur = cur.next
if list1 is not None:
cur.next = list1
elif list2 is not None:
cur.next = list2
return head.next
============================================================================== suppose there are k lists and n elements in each list
solution 1: heap sort, time O(nk * log k), with O(k) heap memeory
tip: how to write comparator for priority_queue, use >
to achieve min heap
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, Cmp> pq;
for (int i = 0; i < lists.size(); i++) {
if (lists[i]) {
pq.push(lists[i]);
lists[i] = lists[i]->next;
}
}
ListNode dummy(0);
ListNode* p = &dummy;
while (! pq.empty()) {
ListNode* node = pq.top();
pq.pop();
if (node->next) pq.push(node->next);
p->next = node;
p = p->next;
}
return dummy.next;
}
private:
class Cmp {
public:
bool operator()(ListNode* node1, ListNode* node2) {
return node1->val > node2->val;
}
};
};
solution 2: take advantage of merge 2 sorted list
(k/2) * 2n
k/2/2 * 4n
.
.
.
-------------
log k times, O(nk) for each time
time is O(nk logk) while not using extra memory
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.empty()) return nullptr;
while (lists.size() > 1) {
int sz = lists.size();
for (int i = 0; i < sz / 2; i++) {
lists[i] = merge2Lists(lists[i], lists.back());
lists.pop_back();
}
}
return lists[0];
}
private:
ListNode* merge2Lists(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* p = &dummy;
while (l1 && l2) {
if (l1->val <= l2->val) {
p->next = l1;
l1 = l1->next;
}
else {
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
l1 ? p->next = l1 : p->next = l2;
return dummy.next;
}
};
solution 3: merge sort
T(K_list) = 2T(K/2_list) + O(NK)
= 4T(K/4_list) + 2O(NK/2) + O(Nk)
= ...
= logKT(1_list) + NKlogK
= NKlogK
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int k = lists.size();
return k == 0 ? nullptr : helper(lists, 0, k - 1);
}
private:
ListNode* helper(vector<ListNode*>& lists, int start, int end) {
if (start == end) {
return lists[start];
}
int mid = start + (end - start) / 2;
ListNode* l1 = helper(lists, start, mid);
ListNode* l2 = helper(lists, mid + 1, end);
return merge2Lists(l1, l2);
}
ListNode* merge2Lists(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* p = &dummy;
while (l1 && l2) {
if (l1->val <= l2->val) {
p->next = l1;
l1 = l1->next;
}
else {
p->next = l2;
l2 = l2->next;
}
p = p->next;
}
l1 ? p->next = l1 : p->next = l2;
return dummy.next;
}
};
follow up: sort k sorted arrays?
- use k pointers to index each array entry 2. find out lowest value among indexed values (O(arrays.num)) 3. push values that are equal to current lowest value into pq (O(log arrays.num)), advance corresponding index (O(arrays.num)).
time is O(N * array.num) where N is total number of elements.
further optimization: same as merge k sorted lists, while in sorted arrays we store the iterator of each entry of array or store (idx of an array in arrays, idx of the stored element in array). Hence, time is same as k sorted list