Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
While the lists is not empty, keep merging the list to the result list. Method to merge two lists is the same as.
Question 54: Merge Two Sorted Lists
ListNode *merge2Lists(ListNode *head1, ListNode *head2){
ListNode *head = new ListNode(INT_MIN);
ListNode *pre = head;
while(head1 != NULL && head2 != NULL){
if(head1->val <= head2->val){
pre->next = head1;
head1 = head1->next;
}else{
pre->next = head2;
head2 = head2->next;
}
pre = pre->next;
}
if(head1 != NULL){
pre->next = head1;
}
if(head2 != NULL){
pre->next = head2;
}
pre = head->next;
delete head;
return pre;
}
ListNode *mergeKLists(vector<ListNode *> &lists) {
if(lists.size() == 0) return NULL;
ListNode *p = lists[0];
for(int i=1; i<lists.size(); i++){
p = merge2Lists(p, lists[i]);
}
return p;
}
java
public ListNode mergeKLists(List<ListNode> lists) {
ListNode head = new ListNode(-1);
ListNode p = head;
if(lists.size()==0) return null;
if(lists.size()==1) return lists.get(0);
ListNode l1 = lists.get(0);
for(int i=1;i<lists.size();i++){
ListNode l2 = lists.get(i);
while(l1!=null && l2!=null){
if(l1.val<l2.val){
p.next = l1;
l1 = l1.next;
p = p.next;
}else{
p.next = l2;
l2 = l2.next;
p = p.next;
}
}
while(l1!=null){
p.next = l1;
p = p.next;
l1 = l1.next;
}
while(l2!=null){
p.next = l2;
p = p.next;
l2 = l2.next;
}
l1 = head.next;
p = head;
}
return head.next;
}
Refactor: Sep/17/2014
Java Recursion
It’s similar to merge sort. For example, assuming we have 4 lists: 1, 2, 3, 4. We can merge 1 and 2 to be a new list 5. And 3 and 4 can be merged to be a new list 6. Finally we merge 5 and 6 to get the result. So in this algorithm, we divide the lists by 2 until its size reaches 1. And then merge them from bottom to top. We have T(n) = 2T(n/2) + kn. So the complexity is O(kn logn). The depth of the recursive function is O(log n).
public ListNode mergeKLists(List<ListNode> lists) {
if(lists.size()<=0) return null;
if(lists.size()==1) return lists.get(0);
return mergeKlists(lists, 0, lists.size()-1);
}
public ListNode mergeKlists(List<ListNode> lists, int left, int right){
if(left<right){
int mid = left+(right-left)/2;
return merge2List(mergeKlists(lists, left, mid), mergeKlists(lists, mid+1, right));
}
return lists.get(left);
}
public ListNode merge2List(ListNode l1, ListNode l2){
ListNode newHead = new ListNode(-1);
ListNode p1 = newHead;
while(l1!=null && l2!=null){
if(l1.val<=l2.val){
p1.next = l1;
l1 = l1.next;
}else {
p1.next = l2;
l2 = l2.next;
}
p1 = p1.next;
}
p1.next = (l1==null) ? l2:l1;
return newHead.next;
}
There is another optimal way using a priority queue. We can add the heads of all lists in to the queue. And we can poll out the smallest one. If the next node of this smallest node is not null, we can add the next node to the queue. We will continue doing this until the queue is empty. Every time we add a new element to the queue, it costs O(log n). And we have k elements. So the complexity is O(k logn) + O(k) = O(k logn). And the space complexity is only O(k). k is the total number of lists, n is length of each linked list.
public ListNode mergeKLists(List<ListNode> lists) {
Comparator<ListNode> listNodeComparator = new Comparator<ListNode>() {
@Override
public int compare(ListNode l1, ListNode l2) {
// TODO Auto-generated method stub
return l1.val-l2.val;
}
};
if(lists.size()==0) return null;
Queue<ListNode> pQueue = new PriorityQueue<>(lists.size(), listNodeComparator);
for(int i=0;i<lists.size();i++){
if(lists.get(i)!=null){
pQueue.add(lists.get(i));
}
}
ListNode head = new ListNode(0);
ListNode p = head;
while(!pQueue.isEmpty()){
ListNode node = pQueue.poll();
p.next = node;
if(node.next!=null){
pQueue.add(node.next);
}
p = p.next;
}
return head.next;
}