Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Analysis
The simplest solution is using PriorityQueue. 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).
Java Solution
public ListNode mergeKLists(ListNode[] lists) { if(lists==null||lists.length==0) return null; PriorityQueue<ListNode> queue = new PriorityQueue<ListNode>(new Comparator<ListNode>(){ public int compare(ListNode l1, ListNode l2){ return l1.val - l2.val; } }); ListNode head = new ListNode(0); ListNode p = head; for(ListNode list: lists){ if(list!=null) queue.offer(list); } while(!queue.isEmpty()){ ListNode n = queue.poll(); p.next = n; p=p.next; if(n.next!=null) queue.offer(n.next); } return head.next; } |
Time: log(k) * n.
k
is number of list and n
is number of total elements.
In addition, from Java 8 comparator definition can be simplified as the following:
Comparator<ListNode> comp = Comparator.comparing(ListNode->ListNode.val); PriorityQueue<ListNode> queue = new PriorityQueue<>(comp); |
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue minHeap=new PriorityQueue();
for(ListNode node:lists){
while(node!=null){
minHeap.add(node.val);
node=node.next;
}
}
ListNode temp=new ListNode(-1);
ListNode head=temp;
while(!minHeap.isEmpty()){
head.next=new ListNode(minHeap.remove());
head=head.next;
}
return temp.next;
}
}
we need to put the remain list to the queue again.
What is the purpose of the following statement:
queue.offer(n.next);
No, it is n*log(k) since n is the number of total elements.
Thanks for sharing this. One question – Shouldn’t the time complexity by (nklog(k)), because ultimately we end up removing O(nk) elements from the priority queue, each time the work being O(log(k))
Yes, the algorithm is perfectly correct.
The head node is just a helper so you can start arranging the sorted list.
I think your algorism is wrong.
why you hard coded the head node as :
ListNode head = new ListNode(0);
if you “return head.next”, you will return null!
And I don’t understand why you write the following , could you explain more? you already write q.add(list), why you write “q.add(temp.next)” again? what’s you purpose?
//keep adding next element of each list
if (temp.next != null)
q.add(temp.next);
———————————————–
ListNode head = new ListNode(0);
ListNode p = head; // serve as a pointer/cursor
while (q.size() > 0) {
ListNode temp = q.poll();
//poll() retrieves and removes the head of the queue – q.
p.next = temp;
//keep adding next element of each list
if (temp.next != null)
q.add(temp.next);
p = p.next;
}
return head.next;,
No.. the factor is log(k)
By doing this you are introducing an extra log(n) factor to your runtime.