Merge K Sorted Lists
DESCRIPTION (credit Leetcode.com)
Given k linked lists, each sorted in ascending order, in a list lists, write a function to merge the input lists into one sorted linked list.
EXAMPLES
Example 1:
Inputs:
lists = [[3,4,6],[2,3,5],[-1,6]] 3 -> 4 -> 6 2 -> 3 -> 5 -1 -> 6
Output:
[-1,2,3,3,4,5,6,6]
-1 -> 2 -> 3 -> 3 -> 4 -> 5 -> 6 -> 6
Explanation
This problem can be solved using a min-heap of size k.
The min-heap will always store the first unmerged node from each of the k sorted linked lists, and the node with the smallest value sits at the root of the heap. We build the merged list we will return at the end by repeatedly popping the root from the heap. Each time we pop from the heap, we will also push the next element from the linked list where the popped element came from onto the heap.
When the heap is empty, all the elements from the linked lists have been merged, and we can return the merged list.
Step 1: Initialize the heap
The first step in the algorithm is to initialize the heap with the first element from each of the k linked lists. We iterate over each of the k linked lists, and for each linked list, we push a tuple containing the value of its head node, its index (in the input list), and the node itself onto the heap.
from heapq import heappush, heappopdef mergeKLists(lists):if not lists:return Noneheap = []for i, node in enumerate(lists):if node:heappush(heap, (node.val, i, node))dummy = ListNode(0)curr = dummywhile heap:val, idx, node = heappop(heap)curr.next = nodecurr = curr.nextif node.next:heappush(heap, (node.next.val, idx, node.next))return dummy.next
Step 2: Build the merged list
With the heap initialized, we can now build the merged linked list. We start by initializing a dummy node that acts as the head of the merged list, and a pointer curr that points to the last node in the merged list (initially the dummy node).
from heapq import heappush, heappopdef mergeKLists(lists):if not lists:return Noneheap = []for i, node in enumerate(lists):if node:heappush(heap, (node.val, i, node))dummy = ListNode(0)curr = dummywhile heap:val, idx, node = heappop(heap)curr.next = nodecurr = curr.nextif node.next:heappush(heap, (node.next.val, idx, node.next))return dummy.next
Now, we can repeatedly pop the root of the heap, which gives us a reference to the node with the smallest value among the first unmerged elements from the k linked lists. We append this node to the merged list and move the pointer curr to the node we just appended.
from heapq import heappush, heappopdef mergeKLists(lists):if not lists:return Noneheap = []for i, node in enumerate(lists):if node:heappush(heap, (node.val, i, node))dummy = ListNode(0)curr = dummywhile heap:val, idx, node = heappop(heap)curr.next = nodecurr = curr.nextif node.next:heappush(heap, (node.next.val, idx, node.next))return dummy.next
Last, to ensure that our heap always contains the first unmerged element from each of the k linked lists, we push the next node from the linked list where the popped node came from onto the heap, if it exists. This prepares the heap for the next iteration.
from heapq import heappush, heappopdef mergeKLists(lists):if not lists:return Noneheap = []for i, node in enumerate(lists):if node:heappush(heap, (node.val, i, node))dummy = ListNode(0)curr = dummywhile heap:val, idx, node = heappop(heap)curr.next = nodecurr = curr.nextif node.next:heappush(heap, (node.next.val, idx, node.next))return dummy.next
When the heap is empty, all the elements from the linked lists have been merged, and we can return head of the the merged list by returning dummy.next.
from heapq import heappush, heappopdef mergeKLists(lists):if not lists:return Noneheap = []for i, node in enumerate(lists):if node:heappush(heap, (node.val, i, node))dummy = ListNode(0)curr = dummywhile heap:val, idx, node = heappop(heap)curr.next = nodecurr = curr.nextif node.next:heappush(heap, (node.next.val, idx, node.next))return dummy.next
Solution
from heapq import heappush, heappopdef mergeKLists(lists):if not lists:return Noneheap = []for i, node in enumerate(lists):if node:heappush(heap, (node.val, i, node))dummy = ListNode(0)curr = dummywhile heap:val, idx, node = heappop(heap)curr.next = nodecurr = curr.nextif node.next:heappush(heap, (node.next.val, idx, node.next))return dummy.next
Complexity Analysis
Time Complexity: O(n * log k), where n is the total number of nodes in each of the input linked lists. We iterate over all the nodes in the linked lists. At each iteration, we push and pop elements from the heap, which takes O(log k) time.
Space Complexity: O(k). We use a min-heap of size k to store the first unmerged element from each of the k linked lists.
Loading comments...