# 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

# Solution

Approach 1: use a priority queue to keep the current heads -- O(N logk).

Approach 2: merge pairs of lists until there's 1 big list left -- O(N logk).

# Code (Python)

Approach 1:

    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        # random.random() just to avoid comparing ListNodes
        heap = [(head.val, random.random(), head) for head in lists if head]
        heapq.heapify(heap)
        
        merged_head = ListNode(0)
        current = merged_head
        while heap:
            val, id, node = heapq.heappop(heap)
            current.next = node
            current = current.next
            if node.next:
                heapq.heappush(heap, (node.next.val, random.random(), node.next))
        
        current.next = None
        return merged_head.next

Approach 2:

    def mergeKLists(self, lists):
        if not lists:
            return None
        lists = collections.deque(lists)
        while len(lists) > 1:
            lists.append(self.merge2Lists(lists.popleft(), lists.popleft()))
        return lists[0]
    
    def merge2Lists(self, l1, l2):
        dummy = ListNode(0)
        current = dummy
        while l1 and l2:
            if l1.val <= l2.val:
                current.next = l1
                l1 = l1.next
            else:
                current.next = l2
                l2 = l2.next
            current = current.next
        if l1:
            current.next = l1
        else:
            current.next = l2
        return dummy.next

# Code (C++)

Approach 1:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
// Compare one by one.
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int n = lists.size();
        vector<ListNode*> p(n, NULL);
        for (int i = 0; i < n; ++i)
        {
            if (lists[i])
                p[i] = lists[i];
        }
        ListNode dummyHead(0);
        ListNode *d = &dummyHead;
        while (true)
        {
            int minIdx = -1;
            for (int i = 0; i < lists.size(); ++i)
            {
                if (p[i] && (minIdx < 0 || p[minIdx]->val > p[i]->val))
                    minIdx = i;
            }
            if (minIdx < 0)
                break;
            d->next = p[minIdx];
            d = d->next;
            p[minIdx] = p[minIdx]->next;
        }
        return dummyHead.next;
    }
};

// Minimum heap.
class Solution {
private:
    struct cmp {
        bool operator() (ListNode *a, ListNode *b) {
            return a->val > b->val;
        }
    };
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int n = lists.size();
        priority_queue<ListNode*, vector<ListNode*>, cmp> q;
        for (int i = 0; i < n; ++i)
        {
            if (lists[i])
                q.push(lists[i]);
        }
        ListNode dummyHead(0);
        ListNode *d = &dummyHead;
        while (!q.empty())
        {
            d->next = q.top();
            d = d->next;
            q.pop();
            if (d->next)
                q.push(d->next);
        }
        return dummyHead.next;
    }
};

Approach 2:

// Merge with divide and conquer.
class Solution {
private:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode dummyNode(0);
        ListNode *d = &dummyNode;
        while (l1 || l2)
        {
            if (l1 == NULL || l2 && l2->val <= l1->val)
            {
                d->next = l2;
                l2 = l2->next;
            }
            else
            {
                d->next = l1;
                l1 = l1->next;
            }
            d = d->next;
        }
        return dummyNode.next;
    }
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        int n = lists.size();
        if (n == 0)
            return NULL;
        for (int interval = 1; interval < n; interval *= 2)
        {
            for (int i = 0; i < n && i + interval < n; i += interval * 2)
            {
                lists[i] = mergeTwoLists(lists[i], lists[i+interval]);
            }
        }
        return lists[0];
    }
};