Leetcode --- Merge k Sorted Lists === ## Description You are given an array of k linked-lists lists, each linked-list is sorted in ascending order. Merge all the linked-lists into one sorted linked-list and return it. ### Examples * Ex1: **Input**: lists = [[1,4,5],[1,3,4],[2,6]] **Output**: [1,1,2,3,4,4,5,6] **Explanation**: The linked-lists are: [ 1->4->5, 1->3->4, 2->6 ] merging them into one sorted list: 1->1->2->3->4->4->5->6 * Ex2: **Input:** lists = [] **Output:** [] * Ex3: **Input**: lists = [[]] **Output**: [] ### Constraints * k == lists.length * 0 <= k <= 10^4^ * 0 <= lists[i].length <= 500 * -10^4^ <= lists[i][j] <= 10^4^ * lists[i] is sorted in ascending order. * The sum of lists[i].length won't exceed 10^4^. ## Solutions * **Method 1 : Brute Force** The idea is that I go through all the nodes in the list and save their values into a new array,and afterwards the whole problem becomes a very easy one at the moment,I just need to sort the values in the array and put these values into each node in the new linked list. ### implement code ```java= /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode mergeKLists(ListNode[] lists) { if(lists.length == 0) return null; for(int i = 0 ; i< lists.length ;i++) { if(lists[i] != null) break; if(i == lists.length -1 ) return null; } //get the size of the list //get the value,which is in the list, to store it in the array int[] tmp = new int[countsize(lists)]; getvalue(lists,tmp); //sort Arrays.sort(tmp); //put the value,which is in the array, into the nodes,which is in the list ListNode ans = new ListNode(); ListNode head = ans; for(int i =0 ; i< tmp.length ;i++) { head.val = tmp[i]; if(i != tmp.length-1) { head.next =new ListNode(); head =head.next; } } return ans; } public int countsize(ListNode[] lists) { int k =0; for(int i =0 ;i< lists.length ; i++) { ListNode tmp = lists[i]; while(tmp != null) { k++; tmp =tmp.next; } } return k; } public void getvalue(ListNode[] lists,int[] arr) { for(int i =0,k=0 ;i< lists.length ; i++) { ListNode tmp = lists[i]; while(tmp != null) { arr[k] = tmp.val; k++; tmp =tmp.next; } } } } ``` ### Complexity Analysis * Time Complexity The getvalue function is executed n times in the for and while loops, where n is the total number of nodes,in term of Big O notation is O(n),and the countsize function is also exactly the same,so O(n) as well. The sort function is costing O(nlogn) in the best case and worse case. Finally, I put the values into the nodes and traverse the entire array, the cost is still O(n). **Total time complexity** O(n) + O(n) + O(nlogn) + O(n) = ==O(nlogn)== where n is the total number of nodes in the list. * Space Complexity I created an array to hold all the values in the node,its size is n,where n is number of nodes in the list,so O(n). What I also allocated is the answer list, which has the same number of nodes as the array,so O(n). **Total Space Complexity** O(n) + O(n) = ==O(n)==,where n is number of the nodes in the list. ### Submission on leetcode Runtime: **2 ms, 89.17%** Memory Usage: **40.3 MB, 81.96%** --- * **Method 2 : Compare one by one** The idea is that I find the minimum value from ListNode array by comparing,then I can put this minimum value in my answer list,and I move the next pointer from the list that has the minimum value.Therefore, I can iteratively perform the above idea and finally find an answer list. ### Implement code ```java= /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode mergeKLists(ListNode[] lists) { //find the biggest vaule at node in every lists if(lists.length == 0) return null; boolean flag = true; for(int i = 0 ; i < lists.length ; i++) { if(lists[i] != null) { flag =false ; break; } } if(flag) return null; ListNode ans = new ListNode(); ListNode head =ans; int MIN_pointer =0; int countNUll = 0; while(countNUll < lists.length) { int min =Integer.MAX_VALUE; countNUll =0; boolean change = false; for(int i = 0 ; i< lists.length ; i++) { if(lists[i] == null ) { countNUll ++; continue; } if(lists[i].val < min) { change = true; min = lists[i].val; MIN_pointer =i; } } if(change) { head.next = new ListNode(min); lists[MIN_pointer] = lists[MIN_pointer].next; head =head.next; } } return ans.next ; } } ``` ### Complexity Analysis * Time Complexity The inner for loop from line 39 to line 53 in the code finds the minimum value of all nodes in the list,so I compare at most n nodes,its cost is O(k),where k is lists.length. The outer while loop is gonna stop if all lists are null,in other words,it will execute all nodes in the list,therefore,its cost is O(n) where n is total number of nodes. **Total time complexity** O(k) * O(n) = ==O(kn)==,where k is lists.length and n is number of nodes in the list. * Space Complexity I only created an answer list,its size is the number of all nodes in the input list,its cost is O(n) where n is total number of nodes. **Total space complexity** ==O(n)== where n is number of nodes in the list. ### Submission on leetcode Runtime: 433 ms Memory Usage: 44.7 MB --- * **Method 3 : Optimize Approach 2 by Priority Queue** Here is a way to accelerate the comparison part of method 2,it uses the specific data structure,Priority Queue. The time complexity of the comparison part can be improved from O(n) to O(logn) ### Implement code ```java= /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ import java.util.*; class Solution { public ListNode mergeKLists(ListNode[] lists) { Comparator<ListNode> cmp = new Comparator<ListNode>(){ @Override public int compare(ListNode l1,ListNode l2) { return l1.val - l2.val; } }; PriorityQueue<ListNode> pq = new PriorityQueue<ListNode>(cmp); for(int i = 0 ; i< lists.length ; i++) { if(lists[i] != null) pq.offer(lists[i]); } ListNode ans = new ListNode(); ListNode head =ans; while(pq.size() != 0) { ListNode tmp = pq.poll(); head.next = tmp; head = head.next ; tmp =tmp.next; if(tmp != null) pq.offer(tmp); } return ans.next; } } ``` ### Complexity Analysis * Time Complexity First of all,I invite the heads of all nodes in the list to our priority queue,its cost is O(k) where k is lists.length. And afterwards,I take the minumum value from priority queue and invite the next node into my priority queue,so these are O(logk) + O(logk),and these above operations must be performed iteratively until all nodes are out of the priority queue,therefore,they are executed n-k times where n is number of nodes and k is lists.length,so the Big O is O(n-k) which is almost equal to O(n),the entire while loop cost O(logk) * O(n) = O(nlogk) **Total time complexity** O(k) + O(nlogk) = ==O(nlogk)== where k is lists.length and n is number of nodes in list. * Space Complexity I created a priority queue and its size at most is k where k is lists.length,and I also created an answer list,it must be the same size as the number of nodes in the input list **Total space complexity** O(k) + O(n) = ==O(n)== where n is number of nodes in list. ### Submission on leetcode Runtime: **3 ms, faster than 82.65%** of Java online submissions for Merge k Sorted Lists. Memory Usage: **40.7 MB, less than 55.72%** of Java online submissions for Merge k Sorted Lists. ###### tags: `Leetcode` `LinkedList` `Hard` `Priority queue`