Problem:
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
Anaysis
For this problem, we can do it from three aspects.
The first and the most intuitive method, we can store all the ListNode into Arrayllist and sort it. Then we add each node to a new LinkList.
time complexity O(nk log nk)
space complexity O(nk) --> the length of the ArrayList
The second method is to find the LIstNode with min-value, and then we move the pointer to the next node.
time complexity O(nk)
space complexity O(1)
The last one seems to be the easiest one. We can use the heap to store the listNode and then pop all of them. Here we should notice that if we store all the ListNode to the heap one time, the space complexity will be O(nk). However, if we store the listNode to heap while popping at each loop. The space complexity will be O(k)
time complexity O(nlogk)
space complexity O(k)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution1 {
// first, by using heap
static class myComparator implements Comparator<ListNode>{
@Override
public int compare (ListNode l1, ListNode l2) {
return l1.val - l2.val;
}
}
public ListNode mergeKLists1(ListNode[] lists) {
// corner case
if (lists.length == 0 || lists == null) {
return null;
}
PriorityQueue<ListNode> heap = new PriorityQueue<>(new myComparator());
for (ListNode head:lists) {
if (head != null) {
heap.offer(head);
}
}
// 本来想把所有的ListNode都存到heap里面, 但是发现空间复杂度太高了, O(nK) 但是时间复杂度为 O(lognk)
// 所以目前用的边存边取的办法,时间复杂度是O(nlogk), 空间复杂度是O(logk)
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while(!heap.isEmpty()) {
tail.next = heap.poll();
if (tail.next.next != null ) {
heap.add(tail.next.next);
}
tail = tail.next;
}
return dummy.next;
}
// second method, put all the listNode into Arraylist, sort, relink
public ListNode mergeKLists2(ListNode[] lists) {
// corner case
if (lists.length == 0 || lists == null) {
return null;
}
ArrayList<ListNode> arr = new ArrayList<>();
for (ListNode head:lists) {
while(head != null) {
arr.add(head);
head = head.next;
}
}
Collections.sort(arr, new Comparator<ListNode>() {
@Override
public int compare(ListNode l1, ListNode l2) {
return l1.val - l2.val;
}
});
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
for (ListNode node:arr) {
tail.next = node;
tail = tail.next;
}
return dummy.next;
}
// third method, I'm gonna use the LinkList directly
public ListNode findMin(ListNode[] lists) {
if (lists.length == 0 || lists == null) {
return null;
}
int min = Integer.MAX_VALUE;
int flag = -1;
for (int i=0; i<lists.length; i++) {
if (lists[i] == null){
continue;
}
if (lists[i].val < min) {
min = lists[i].val;
flag = i;
}
}
ListNode temp = null;
if (flag != -1){
temp = lists[flag];
lists[flag] = lists[flag].next;
}
return temp;
}
public ListNode mergeKLists3(ListNode[] lists) {
if (lists.length == 0 || lists == null) {
return null;
}
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
ListNode temp = null;
// 此处要保证每次 findMin 的 ListNode 不是空
do{
temp = findMin(lists);
tail.next = temp;
tail = tail.next;
}while(temp != null);
return dummy.next;
}
}