[Naive Approach] Repeatedly Select the Min - O(n*k) Time and O(1) Space
The idea is to iterate through all the k head nodes and do the following until all nodes are processed.
Append the head node with minimum value to the resultant list.
Increment the head to next node.
Step by step approach:
Initialize a dummy head for the resultant list.
Find the node with the smallest value in all the k lists.
Increment the current pointer to the next node of the list where the smallest node is found.
Append the node with smallest value to the resultant list.
Repeat these steps till all nodes have been used.
C++
#include<iostream>#include<vector>usingnamespacestd;classNode{public:intdata;Node*next;Node(intx){data=x;next=nullptr;}};Node*mergeKLists(vector<Node*>&arr){Nodedummy(0);Node*tail=&dummy;while(true){intminIndex=-1;// Find the minimum current nodefor(inti=0;i<arr.size();i++){if(arr[i]!=nullptr&&(minIndex==-1||arr[i]->data<arr[minIndex]->data)){minIndex=i;}}if(minIndex==-1)break;tail->next=arr[minIndex];tail=tail->next;arr[minIndex]=arr[minIndex]->next;}returndummy.next;}intmain(){vector<vector<int>>lists={{1,4,7},{2,8},{3,9}};vector<Node*>arr;// Convert each array into a linked listfor(constauto&row:lists){Node*head=nullptr;Node*temp=nullptr;for(intx:row){Node*newNode=newNode(x);if(head==nullptr){head=newNode;temp=newNode;}else{temp->next=newNode;temp=temp->next;}}arr.push_back(head);}Node*res=mergeKLists(arr);// Print the merged linked listwhile(res!=nullptr){cout<<res->data;if(res->next!=nullptr)cout<<" -> ";res=res->next;}cout<<"\n";return0;}
Java
importjava.util.*;classNode{intdata;Nodenext;Node(intx){data=x;next=null;}}classGFG{staticNodemergeKLists(Node[]arr){Nodedummy=newNode(0);Nodetail=dummy;while(true){intminIndex=-1;// Find the minimum current nodefor(inti=0;i<arr.length;i++){if(arr[i]!=null&&(minIndex==-1||arr[i].data<arr[minIndex].data)){minIndex=i;}}if(minIndex==-1)break;tail.next=arr[minIndex];tail=tail.next;arr[minIndex]=arr[minIndex].next;}returndummy.next;}publicstaticvoidmain(String[]args){int[][]lists={{1,4,7},{2,8},{3,9}};Node[]arr=newNode[lists.length];// Convert each array into a linked listfor(inti=0;i<lists.length;i++){Nodehead=null;Nodetemp=null;for(intx:lists[i]){NodenewNode=newNode(x);if(head==null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr[i]=head;}Noderes=mergeKLists(arr);// Print the merged linked listwhile(res!=null){System.out.print(res.data);if(res.next!=null)System.out.print(" -> ");res=res.next;}System.out.println();}}
Python
classNode:def__init__(self,x):self.data=xself.next=NonedefmergeKLists(arr):dummy=Node(0)tail=dummywhileTrue:min_index=-1# Find the minimum current nodeforiinrange(len(arr)):ifarr[i]isnotNoneand(min_index==-1orarr[i].data<arr[min_index].data):min_index=iifmin_index==-1:breaktail.next=arr[min_index]tail=tail.nextarr[min_index]=arr[min_index].nextreturndummy.next# Driver Codeif__name__=="__main__":lists=[[1,4,7],[2,8],[3,9]]arr=[]# Convert each array into a linked listforrowinlists:head=Nonetemp=Noneforxinrow:new_node=Node(x)ifheadisNone:head=new_nodetemp=new_nodeelse:temp.next=new_nodetemp=temp.nextarr.append(head)res=mergeKLists(arr)# Print the merged linked listwhileresisnotNone:print(res.data,end="")ifres.nextisnotNone:print(" -> ",end="")res=res.nextprint()
C#
usingSystem;classNode{publicintdata;publicNodenext;publicNode(intx){data=x;next=null;}}classGFG{staticNodemergeKLists(Node[]arr){Nodedummy=newNode(0);Nodetail=dummy;while(true){intminIndex=-1;// Find the minimum current nodefor(inti=0;i<arr.Length;i++){if(arr[i]!=null&&(minIndex==-1||arr[i].data<arr[minIndex].data)){minIndex=i;}}if(minIndex==-1)break;tail.next=arr[minIndex];tail=tail.next;arr[minIndex]=arr[minIndex].next;}returndummy.next;}publicstaticvoidMain(){int[][]lists={newint[]{1,4,7},newint[]{2,8},newint[]{3,9}};Node[]arr=newNode[lists.Length];// Convert each array into a linked listfor(inti=0;i<lists.Length;i++){Nodehead=null;Nodetemp=null;foreach(intxinlists[i]){NodenewNode=newNode(x);if(head==null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr[i]=head;}Noderes=mergeKLists(arr);// Print the merged linked listwhile(res!=null){Console.Write(res.data);if(res.next!=null)Console.Write(" -> ");res=res.next;}Console.WriteLine();}}
JavaScript
classNode{constructor(x){this.data=x;this.next=null;}}functionmergeKLists(arr){letdummy=newNode(0);lettail=dummy;while(true){letminIndex=-1;// Find the minimum current nodefor(leti=0;i<arr.length;i++){if(arr[i]!==null&&(minIndex===-1||arr[i].data<arr[minIndex].data)){minIndex=i;}}if(minIndex===-1)break;tail.next=arr[minIndex];tail=tail.next;arr[minIndex]=arr[minIndex].next;}returndummy.next;}// Driver codeletlists=[[1,4,7],[2,8],[3,9]];letarr=[];// Convert each array into a linked listfor(letrowoflists){lethead=null;lettemp=null;for(letxofrow){letnewNode=newNode(x);if(head===null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr.push(head);}letres=mergeKLists(arr);letoutput="";while(res!==null){output+=res.data;if(res.next!==null)output+=" -> ";res=res.next;}console.log(output);
Output
1 -> 2 -> 3 -> 4 -> 7 -> 8 -> 9
[Expected Approach - 1] Min Heap - O(n * log k) Time and O(k) Space
This solution is mainly an optimization over the previous approach. Instead of linearly traversing the array to find the minimum, we use min heap data structure and reduce the time complexity of this operation to O(log k).
This one works better for unequal sized lists.
Step by step approach:
Insert the head node of each non-empty linked list into the min-heap.
Extract the node with the smallest value from the min-heap.
Append the extracted node to the resultant list.
If the extracted node has a next node, insert that next node into the min-heap.
Repeat steps 2–4 until the min-heap becomes empty, then return dummy->next.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*next;Node(intx){data=x;next=nullptr;}};Node*mergeKLists(vector<Node*>&arr){// Define the comparator inside the functionautocompare=[](Node*a,Node*b){returna->data>b->data;};priority_queue<Node*,vector<Node*>,decltype(compare)>pq(compare);// Insert the head nodes of k listsfor(Node*head:arr){if(head!=nullptr)pq.push(head);}// Initialize a dummy headNodedummy(-1);Node*tail=&dummy;while(!pq.empty()){// Pop the minimum nodeNode*top=pq.top();pq.pop();// Append the node to the merged listtail->next=top;tail=top;// Insert the next node from the same listif(top->next!=nullptr)pq.push(top->next);}// Terminate the merged listtail->next=nullptr;returndummy.next;}intmain(){vector<vector<int>>lists={{1,4,7},{2,8},{3,9}};vector<Node*>arr;// Convert arrays into linked listsfor(constauto&row:lists){Node*head=nullptr;Node*temp=nullptr;for(intx:row){Node*newNode=newNode(x);if(head==nullptr){head=newNode;temp=newNode;}else{temp->next=newNode;temp=temp->next;}}arr.push_back(head);}// Merge the k sorted linked listsNode*res=mergeKLists(arr);// Print the merged listwhile(res!=nullptr){cout<<res->data;if(res->next!=nullptr)cout<<" -> ";res=res->next;}cout<<'\n';return0;}
Java
importjava.util.*;classNode{intdata;Nodenext;Node(intx){data=x;next=null;}}classGFG{staticNodemergeKLists(Node[]arr){// Define the comparator inside the functionPriorityQueue<Node>pq=newPriorityQueue<>((a,b)->Integer.compare(a.data,b.data));// Insert the head nodes of k listsfor(Nodehead:arr){if(head!=null)pq.add(head);}// Initialize a dummy headNodedummy=newNode(-1);Nodetail=dummy;while(!pq.isEmpty()){// Pop the minimum nodeNodetop=pq.poll();// Append the node to the merged listtail.next=top;tail=top;// Insert the next node from the same listif(top.next!=null)pq.add(top.next);}// Terminate the merged listtail.next=null;returndummy.next;}publicstaticvoidmain(String[]args){int[][]lists={{1,4,7},{2,8},{3,9}};Node[]arr=newNode[lists.length];// Convert arrays into linked listsfor(inti=0;i<lists.length;i++){Nodehead=null;Nodetemp=null;for(intx:lists[i]){NodenewNode=newNode(x);if(head==null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr[i]=head;}// Merge the k sorted linked listsNoderes=mergeKLists(arr);// Print the merged listwhile(res!=null){System.out.print(res.data);if(res.next!=null)System.out.print(" -> ");res=res.next;}System.out.println();}}
Python
importheapqclassNode:def__init__(self,x):self.data=xself.next=NonedefmergeKLists(arr):pq=[]# Insert the head nodes of all listsforiinrange(len(arr)):head=arr[i]ifheadisnotNone:heapq.heappush(pq,(head.data,i,head))# Dummy node for the merged listdummy=Node(-1)tail=dummywhilepq:_,index,top=heapq.heappop(pq)# Add node to merged listtail.next=toptail=top# Add next node of the current listiftop.nextisnotNone:heapq.heappush(pq,(top.next.data,index,top.next))# Terminate the merged listtail.next=Nonereturndummy.nextdefmain():lists=[[1,4,7],[2,8],[3,9]]arr=[]# Convert arrays into linked listsforrowinlists:head=Nonetemp=Noneforxinrow:newNode=Node(x)ifheadisNone:head=newNodetemp=newNodeelse:temp.next=newNodetemp=temp.nextarr.append(head)# Merge the k sorted linked listsres=mergeKLists(arr)# Print the merged listwhileresisnotNone:print(res.data,end="")ifres.nextisnotNone:print(" -> ",end="")res=res.nextprint()# Driver Codeif__name__=="__main__":main()
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodenext;publicNode(intx){data=x;next=null;}}classGFG{staticNodemergeKLists(Node[]arr){// Define the comparator inside the functionPriorityQueue<Node,int>pq=newPriorityQueue<Node,int>();// Insert the head nodes of k listsforeach(Nodeheadinarr){if(head!=null)pq.Enqueue(head,head.data);}// Initialize a dummy headNodedummy=newNode(-1);Nodetail=dummy;while(pq.Count>0){// Pop the minimum nodeNodetop=pq.Dequeue();// Append the node to the merged listtail.next=top;tail=top;// Insert the next node from the same listif(top.next!=null)pq.Enqueue(top.next,top.next.data);}// Terminate the merged listtail.next=null;returndummy.next;}staticvoidMain(){int[][]lists={newint[]{1,4,7},newint[]{2,8},newint[]{3,9}};Node[]arr=newNode[lists.Length];// Convert arrays into linked listsfor(inti=0;i<lists.Length;i++){Nodehead=null;Nodetemp=null;foreach(intxinlists[i]){NodenewNode=newNode(x);if(head==null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr[i]=head;}// Merge the k sorted linked listsNoderes=mergeKLists(arr);// Print the merged listwhile(res!=null){Console.Write(res.data);if(res.next!=null)Console.Write(" -> ");res=res.next;}Console.WriteLine();}}
JavaScript
classNode{constructor(x){this.data=x;this.next=null;}}classPriorityQueue{constructor(compare){this.heap=[];this.compare=compare;}enqueue(value){this.heap.push(value);this.bubbleUp();}bubbleUp(){letindex=this.heap.length-1;while(index>0){letparentIndex=Math.floor((index-1)/2);letelement=this.heap[index];letparent=this.heap[parentIndex];if(this.compare(element,parent)>=0)break;this.heap[index]=parent;this.heap[parentIndex]=element;index=parentIndex;}}dequeue(){lettop=this.heap[0];letend=this.heap.pop();if(this.heap.length>0){this.heap[0]=end;this.sinkDown(0);}returntop;}sinkDown(index){letleft=2*index+1;letright=2*index+2;letsmallest=index;if(left<this.heap.length&&this.compare(this.heap[left],this.heap[smallest])<0){smallest=left;}if(right<this.heap.length&&this.compare(this.heap[right],this.heap[smallest])<0){smallest=right;}if(smallest!==index){[this.heap[index],this.heap[smallest]]=[this.heap[smallest],this.heap[index]];this.sinkDown(smallest);}}isEmpty(){returnthis.heap.length===0;}}functionmergeKLists(arr){// Define the comparator inside the functionconstcompare=(a,b)=>a.data-b.data;constpq=newPriorityQueue(compare);// Insert the head nodes of k listsfor(letheadofarr){if(head!==null)pq.enqueue(head);}// Initialize a dummy headletdummy=newNode(-1);lettail=dummy;while(!pq.isEmpty()){// Pop the minimum nodelettop=pq.dequeue();// Append the node to the merged listtail.next=top;tail=top;// Insert the next node from the same listif(top.next!==null)pq.enqueue(top.next);}// Terminate the merged listtail.next=null;returndummy.next;}// Driver Codefunctionmain(){constlists=[[1,4,7],[2,8],[3,9]];constarr=[];// Convert arrays into linked listsfor(constrowoflists){lethead=null;lettemp=null;for(constxofrow){constnewNode=newNode(x);if(head===null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr.push(head);}// Merge the k sorted linked listsletres=mergeKLists(arr);// Print the merged listletoutput=[];while(res!==null){output.push(res.data);res=res.next;}console.log(output.join(" -> "));}main();
Output
1 -> 2 -> 3 -> 4 -> 7 -> 8 -> 9
[ExpectedApproach- 2]DivideandConquer - O(n * log k) Time and O(log k) Space
Recursively split the k lists into two halves until we have pairs of lists to merge.
Then merge these pairs using a two-way merge procedure (similar to merge sort's merge step), and continue this process back up through the recursion tree until all lists are merged into a single sorted list.
This one works better for equal sized lists.
Step by step approach:
Split k lists into two parts: lists[0...mid] and lists[mid+1...end].
Recursively merge the left half of lists to get first sorted list.
Recursively merge the right half of lists to get second sorted list.
Merge the above two sorted lists using two-pointer approach.
Return the final merged sorted list.
C++
#include<bits/stdc++.h>usingnamespacestd;classNode{public:intdata;Node*next;Node(intx){data=x;next=nullptr;}};Node*mergeTwoLists(Node*a,Node*b){Nodedummy(-1);Node*tail=&dummy;// Merge both lists by selecting the smaller nodewhile(a!=nullptr&&b!=nullptr){if(a->data<=b->data){tail->next=a;a=a->next;}else{tail->next=b;b=b->next;}tail=tail->next;}// Attach the remaining nodesif(a!=nullptr)tail->next=a;elsetail->next=b;returndummy.next;}Node*mergeRange(vector<Node*>&arr,intleft,intright){// If the range is emptyif(left>right)returnnullptr;// If only one list remainsif(left==right)returnarr[left];// Divide the range into two halvesintmid=left+(right-left)/2;Node*first=mergeRange(arr,left,mid);Node*second=mergeRange(arr,mid+1,right);// Merge the results of both halvesreturnmergeTwoLists(first,second);}Node*mergeKLists(vector<Node*>&arr){// Handle an empty array of listsif(arr.empty())returnnullptr;// Merge all lists using divide and conquerreturnmergeRange(arr,0,arr.size()-1);}intmain(){vector<vector<int>>lists={{1,4,7},{2,8},{3,9}};vector<Node*>arr;// Convert arrays into linked listsfor(constauto&row:lists){Node*head=nullptr;Node*temp=nullptr;for(intx:row){Node*newNode=newNode(x);if(head==nullptr){head=newNode;temp=newNode;}else{temp->next=newNode;temp=temp->next;}}arr.push_back(head);}// Merge the k sorted linked listsNode*res=mergeKLists(arr);// Print the merged listwhile(res!=nullptr){cout<<res->data;if(res->next!=nullptr)cout<<" -> ";res=res->next;}cout<<'\n';return0;}
Java
classNode{intdata;Nodenext;Node(intx){data=x;next=null;}}classGFG{staticNodemergeTwoLists(Nodea,Nodeb){Nodedummy=newNode(-1);Nodetail=dummy;// Merge both lists by selecting the smaller nodewhile(a!=null&&b!=null){if(a.data<=b.data){tail.next=a;a=a.next;}else{tail.next=b;b=b.next;}tail=tail.next;}// Attach the remaining nodesif(a!=null)tail.next=a;elsetail.next=b;returndummy.next;}staticNodemergeRange(Node[]arr,intleft,intright){// If the range is emptyif(left>right)returnnull;// If only one list remainsif(left==right)returnarr[left];// Divide the range into two halvesintmid=left+(right-left)/2;Nodefirst=mergeRange(arr,left,mid);Nodesecond=mergeRange(arr,mid+1,right);// Merge the results of both halvesreturnmergeTwoLists(first,second);}staticNodemergeKLists(Node[]arr){// Handle an empty array of listsif(arr.length==0)returnnull;// Merge all lists using divide and conquerreturnmergeRange(arr,0,arr.length-1);}publicstaticvoidmain(String[]args){int[][]lists={{1,4,7},{2,8},{3,9}};Node[]arr=newNode[lists.length];// Convert arrays into linked listsfor(inti=0;i<lists.length;i++){Nodehead=null;Nodetemp=null;for(intx:lists[i]){NodenewNode=newNode(x);if(head==null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr[i]=head;}// Merge the k sorted linked listsNoderes=mergeKLists(arr);// Print the merged listwhile(res!=null){System.out.print(res.data);if(res.next!=null)System.out.print(" -> ");res=res.next;}System.out.println();}}
Python
classNode:def__init__(self,x):self.data=xself.next=NonedefmergeTwoLists(a,b):dummy=Node(-1)tail=dummy# Merge both lists by selecting the smaller nodewhileaisnotNoneandbisnotNone:ifa.data<=b.data:tail.next=aa=a.nextelse:tail.next=bb=b.nexttail=tail.next# Attach the remaining nodesifaisnotNone:tail.next=aelse:tail.next=breturndummy.nextdefmergeRange(arr,left,right):# If the range is emptyifleft>right:returnNone# If only one list remainsifleft==right:returnarr[left]# Divide the range into two halvesmid=left+(right-left)//2first=mergeRange(arr,left,mid)second=mergeRange(arr,mid+1,right)# Merge the results of both halvesreturnmergeTwoLists(first,second)defmergeKLists(arr):# Handle an empty array of listsiflen(arr)==0:returnNone# Merge all lists using divide and conquerreturnmergeRange(arr,0,len(arr)-1)defmain():lists=[[1,4,7],[2,8],[3,9]]arr=[]# Convert arrays into linked listsforrowinlists:head=Nonetemp=Noneforxinrow:newNode=Node(x)ifheadisNone:head=newNodetemp=newNodeelse:temp.next=newNodetemp=temp.nextarr.append(head)# Merge the k sorted linked listsres=mergeKLists(arr)# Print the merged listwhileresisnotNone:print(res.data,end="")ifres.nextisnotNone:print(" -> ",end="")res=res.nextprint()# Driver Codeif__name__=="__main__":main()
C#
usingSystem;classNode{publicintdata;publicNodenext;publicNode(intx){data=x;next=null;}}classGFG{staticNodemergeTwoLists(Nodea,Nodeb){Nodedummy=newNode(-1);Nodetail=dummy;// Merge both lists by selecting the smaller nodewhile(a!=null&&b!=null){if(a.data<=b.data){tail.next=a;a=a.next;}else{tail.next=b;b=b.next;}tail=tail.next;}// Attach the remaining nodesif(a!=null)tail.next=a;elsetail.next=b;returndummy.next;}staticNodemergeRange(Node[]arr,intleft,intright){// If the range is emptyif(left>right)returnnull;// If only one list remainsif(left==right)returnarr[left];// Divide the range into two halvesintmid=left+(right-left)/2;Nodefirst=mergeRange(arr,left,mid);Nodesecond=mergeRange(arr,mid+1,right);// Merge the results of both halvesreturnmergeTwoLists(first,second);}staticNodemergeKLists(Node[]arr){// Handle an empty array of listsif(arr.Length==0)returnnull;// Merge all lists using divide and conquerreturnmergeRange(arr,0,arr.Length-1);}staticvoidMain(){int[][]lists={newint[]{1,4,7},newint[]{2,8},newint[]{3,9}};Node[]arr=newNode[lists.Length];// Convert arrays into linked listsfor(inti=0;i<lists.Length;i++){Nodehead=null;Nodetemp=null;foreach(intxinlists[i]){NodenewNode=newNode(x);if(head==null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr[i]=head;}// Merge the k sorted linked listsNoderes=mergeKLists(arr);// Print the merged listwhile(res!=null){Console.Write(res.data);if(res.next!=null)Console.Write(" -> ");res=res.next;}Console.WriteLine();}}
JavaScript
classNode{constructor(x){this.data=x;this.next=null;}}functionmergeTwoLists(a,b){letdummy=newNode(-1);lettail=dummy;// Merge both lists by selecting the smaller nodewhile(a!==null&&b!==null){if(a.data<=b.data){tail.next=a;a=a.next;}else{tail.next=b;b=b.next;}tail=tail.next;}// Attach the remaining nodesif(a!==null)tail.next=a;elsetail.next=b;returndummy.next;}functionmergeRange(arr,left,right){// If the range is emptyif(left>right)returnnull;// If only one list remainsif(left===right)returnarr[left];// Divide the range into two halvesletmid=left+Math.floor((right-left)/2);letfirst=mergeRange(arr,left,mid);letsecond=mergeRange(arr,mid+1,right);// Merge the results of both halvesreturnmergeTwoLists(first,second);}functionmergeKLists(arr){// Handle an empty array of listsif(arr.length===0)returnnull;// Merge all lists using divide and conquerreturnmergeRange(arr,0,arr.length-1);}// Driver Codefunctionmain(){constlists=[[1,4,7],[2,8],[3,9]];constarr=[];// Convert arrays into linked listsfor(constrowoflists){lethead=null;lettemp=null;for(constxofrow){constnewNode=newNode(x);if(head===null){head=newNode;temp=newNode;}else{temp.next=newNode;temp=temp.next;}}arr.push(head);}// Merge the k sorted linked listsletres=mergeKLists(arr);// Print the merged listletoutput=[];while(res!==null){output.push(res.data);res=res.next;}console.log(output.join(" -> "));}main();