Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example
Solution 1: Brute Force
Consideration
- we use a pre pointer to point to the current node that would add next node
- We compare the current merged node with the new list node
- If the new list node is smaller, we need to let the new list node to be the next of the current node. And repeat the comparison.
- After the comparison, if the new list node is not empty, add it to the end of the merged node list.
Time Complexity:O(kn) where k is the length of lists and N is the longest length of any list node, Space complexity: O(kn)
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0)
return null;
ListNode dummy = new ListNode(0);
dummy.next = lists[0];
for(int i = 1; i < lists.length; i++) {
ListNode temp = lists[i];
ListNode pre = dummy;
ListNode merged = dummy.next;
while(merged!=null && temp != null) {
if(temp.val < merged.val) {
pre.next = temp;
temp = temp.next;
pre.next.next = merged;
pre = pre.next;
} else {
pre = merged;
merged = merged.next;
}
}
if(temp!=null)
pre.next = temp;
}
return dummy.next;
}
}
Solution 2: Brute Force 2
Consideration
- we use a integer list to store all value nodes in the node list
- we then use sort function to sort the integer list
- finally, we add all values to the list node
Time complexity
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0)
return null;
ListNode dummy = new ListNode(0);
ListNode head = dummy;
List<Integer> all = new ArrayList();
for(int i = 0; i < lists.length; i++) {
ListNode node = lists[i];
while(node != null) {
all.add(node.val);
node = node.next;
}
}
Collections.sort(all);
for(int i : all) {
head.next = new ListNode(i);
head = head.next;
}
return dummy.next;
}
}
Solution 3: Compare every k node and get the minimal one
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0)
return null;
ListNode dummy = new ListNode(0);
ListNode head = dummy;
while(true) {
boolean breakFlag = true;
int min = Integer.MAX_VALUE;
int min_index = -1;
for(int i = 0; i < lists.length; i++) {
if(lists[i] != null) {
if(lists[i].val < min) {
min = lists[i].val;
min_index = i;
}
breakFlag = false;
}
}
if(breakFlag)
break;
head.next = lists[min_index];
head = head.next;
lists[min_index] = lists[min_index].next;
}
return dummy.next;
}
}
Solution 4: Optimize Approach 3 by Priority Queue
Consideration
- We create a priority queue (FIFO) to store the k min values of the list nodes
- Each time, we add the min one to the merged list and add the next of the min one to the priority queue
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
Comparator<ListNode> cmp;
cmp = new Comparator<ListNode>() {
@Override
public int compare(ListNode node1, ListNode node2) {
// TODO Auto-generated method stub
return node1.val-node2.val;
}
};
//create the queue
Queue<ListNode> que = new PriorityQueue(cmp);
for(ListNode o:lists){
if(o!=null)
que.add(o);
}
ListNode dummy = new ListNode(0);
ListNode head = dummy;
while(!que.isEmpty()) {
head.next = que.poll();
head = head.next;
ListNode next = head.next;
if(next!=null) {
que.add(next);
}
}
return dummy.next;
}
}
Solution 5: Merge lists one by one
In fact, this solution is the same as solution 1
Consideration
- Convert merge k lists problem to merge 2 lists (k-1) times.
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0)
return null;
if(lists.length==1)
return lists[0];
ListNode head = mergeTwo(lists[0], lists[1]);
for(int i = 2; i < lists.length; i++)
head = mergeTwo(head, lists[i]);
return head;
}
private ListNode mergeTwo(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode head = dummy;
while(l1!=null && l2!=null) {
if(l1.val <= l2.val) {
head.next = l1;
l1 = l1.next;
} else {
head.next = l2;
l2 = l2.next;
}
head = head.next;
}
if(l1!=null)
head.next = l1;
if(l2!=null)
head.next = l2;
return dummy.next;
}
}
Solution 6: Merge with Divide And Conquer
Consideration
- We can improve solution 5 by merge pairs
- Each time we merge each pair lists of the node lists until the merged list is only one.
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0)
return null;
int interval = 1;
while(interval < lists.length) {
for(int i = 0; i+interval < lists.length; i+= 2*interval) {
lists[i] = mergeTwo(lists[i], lists[i+interval]);
}
interval*=2;
}
return lists[0];
}
private ListNode mergeTwo(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode head = dummy;
while(l1!=null && l2!=null) {
if(l1.val <= l2.val) {
head.next = l1;
l1 = l1.next;
} else {
head.next = l2;
l2 = l2.next;
}
head = head.next;
}
if(l1!=null)
head.next = l1;
if(l2!=null)
head.next = l2;
return dummy.next;
}
}
References