Input: lists =[[1,4,5],[1,3,4],[2,6]]Output: [1,1,2,3,4,4,5,6]Explanation: The linked-lists are:[1->4->5,1->3->4,2->6]merging them into one sorted list:1->1->2->3->4->4->5->6
Here is the video explaining below methods in detail. Please check it out:
Method 1 - Using merge 2 lists solution sequentially#
We have already solved Merge Two Sorted Lists. The naive approach involves merging the k sorted linked lists by iteratively merging two lists at a time. This approach is simple but less efficient compared to the optimal solution. Here’s how it works:
Sequentially Merge Two Lists at a Time:
Start with the first two linked lists.
Merge them into a single sorted list.
Continue merging the result with the next linked list, until all k lists are merged.
Merge Two Sorted Lists:
Use the technique for merging two sorted linked lists.
Compare the values at the current nodes of both lists, and append the smaller node to the result list.
Move to the next node in the list that contributed the smaller node.
⏰ Time complexity: O(n*k). Each merge operation takes O(n) where n is the total number of nodes across all linked lists. Merging k linked lists sequentially results in:
O(nk)
This is due to k - 1 merge operations.
🧺 Space complexity: O(1). This approach uses no additional data structures apart from the output linked list nodes.
Method 2 - Using Merge sort Divide and Conquer (recursive)#
So, we will keep on merging 2 lists at a time, till we have 1 list remaining.
So, initially we will have k/2 lists remaining, then k/4 and finally after some time 1 remaining.
We take O(n) time to merging 2 sorted lists, finally we have time complexity of O(n * log k).
public ListNode mergeKLists(ListNode[] lists) {
if (lists ==null|| lists.length== 0)
returnnull;
int k = lists.length;
while(k>=1){
// pick 1 list from start, another for end.for(int i = 0; i < k/2; i++){
ListNode l1 = lists[i];
ListNode l2 = lists[k-i-1];
lists[i]= mergeTwoLists(l1, l2);
}
// we have to now process remaining k/2 list k = k /2;
}
return lists[0];
}
1
2
3
4
5
6
7
8
9
public ListNode mergeKLists(ListNode[] lists) {
if(lists==null|| lists.length==0) returnnull;
for(int step = 1; step < lists.length; step <<= 1) {
for(int i = 0; i < lists.length-step; i += 2*step)
lists[i]= mergeTwoLists(lists[i], lists[i+step]);
}
return lists[0];
}
We should add heads of all k sorted lists. At every instant, you need the minimum of the head of all the k linked list. Once you know the minimum, you can push the node to your answer list, and move over to the next node in that linked list.
The simplest solution is using PriorityQueue as min heap. The elements of the priority queue are ordered according to their natural ordering, or by a comparator provided at the construction time (in this case).
classSolution {
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> minHeap =new PriorityQueue<>(
(a, b) -> Integer.compare(a.val, b.val) // Compare nodes by their value );
// Add the head nodes of all lists to the priority queuefor (ListNode head : lists) {
if (head !=null) {
minHeap.add(head);
}
}
ListNode dummy =new ListNode(-1);
ListNode ans = dummy;
while (!minHeap.isEmpty()) {
// Extract the smallest node ListNode node = minHeap.poll();
ans.next= node;
ans = ans.next;
// If the node has a next element, add it to the heapif (node.next!=null) {
minHeap.add(node.next);
}
}
return dummy.next;
}
}
classSolution:
defmergeKLists(self, lists: List[Optional['ListNode']]) -> Optional['ListNode']:
# Create a min-heap min_heap: List[Tuple[int, int, ListNode]] = []
# Add the head nodes of all linked lists to the heap (value, index, node)for i, head in enumerate(lists):
if head:
heapq.heappush(min_heap, (head.val, i, head))
dummy = ListNode(-1)
ans = dummy
while min_heap:
# Extract the smallest node (value, index, node) _, i, node = heapq.heappop(min_heap)
ans.next = node
ans = ans.next
# If the extracted node has a next node, insert its next node into the heapif node.next:
heapq.heappush(min_heap, (node.next.val, i, node.next))
return dummy.next