Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
这道题,第一次刷是过了,第二次同样的代码超时了,看来case是在不断加强的
算法
思路1:
最土的算法,两个月前能过,现在TLE,同[leetcode]Merge Two Sorted Lists,
首先把l1和l2合并到l1中,遍历2n个节点
再把合并之后的l1和l3合并到l1中,遍历3n个节点
再把合并之后的l1和l4合并到l1中,遍历4n个节点
....
最后把合并后的l1和lm合并到l1中,遍历m*n个节点
总共遍历了(2+3+...+m)*n个节点,时间复杂度为O(n*m^2)
代码如下:
1 public ListNode mergeKLists(List<ListNode> lists) { 2 if(lists == null || lists.size() == 0) return null; 3 ListNode l1 = lists.get(0); 4 for(int i = 1; i < lists.size(); i++) 5 l1 = mergeTwoLists(l1,lists.get(i)); 6 return l1; 7 } 8 public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 9 if(l1 == null) return l2; 10 if(l2 == null) return l1; 11 ListNode head = new ListNode(1); 12 head.next = l1; 13 ListNode pre = head; 14 ListNode node = l2; 15 while(l2 != null){ 16 node = l2; 17 while(pre.next != null && pre.next.val <= node.val){ 18 pre = pre.next; 19 } 20 l2 = node.next; 21 node.next = pre.next; 22 pre.next = node; 23 pre = node; 24 } 25 return head.next; 26 }
思路2:
分治法,将m个list分成两拨list1,list2,对每一拨分别处理
当list.size() = 1时,直接返回, size() = 2时候,即:merge2ListNode
处理完list1 和list2之后,再把二者合并
时间负责度O(n*klogk)【其中k为list.size()】
代码如下:
1 public class Solution { 2 public ListNode mergeKLists(List<ListNode> lists) { 3 if(lists == null || lists.size() == 0) return null; 4 if(lists.size() == 1) return lists.get(0); 5 if(lists.size() == 2){ 6 return merge2List(lists.get(0), lists.get(1)); 7 } 8 List<ListNode> l1 = new ArrayList<ListNode>(); 9 List<ListNode> l2 = new ArrayList<ListNode>(); 10 for(int i = 0;i < lists.size() ; i++){ 11 if(i < lists.size() / 2) l1.add(lists.get(i)); 12 else l2.add(lists.get(i)); 13 } 14 ListNode list1 = mergeKLists(l1); 15 ListNode list2 = mergeKLists(l2); 16 return merge2List(list1, list2); 17 } 18 private ListNode merge2List(ListNode l1,ListNode l2){ 19 ListNode head = new ListNode(1); 20 head.next = l1; 21 ListNode pre = head; 22 ListNode node = l2; 23 while(l2 != null){ 24 node = l2; 25 while(pre.next != null && pre.next.val <= node.val){ 26 pre = pre.next; 27 } 28 l2 = node.next; 29 node.next = pre.next; 30 pre.next = node; 31 pre = node; 32 } 33 return head.next; 34 } 35 }
思路3:
堆,由于对堆不熟悉,所以写出来的代码很丑,不过好歹AC了,时间复杂度同分治法,明天过来再优化一下:
渣代码如下:
1 public class Solution { 2 public ListNode mergeKLists(List<ListNode> lists) { 3 if(lists == null || lists.size() == 0) return null; 4 int k = 0; 5 List<ListNode> list = new ArrayList<ListNode>(); 6 for(int i = 0; i < lists.size(); i++){ 7 if(lists.get(i) != null) { 8 k++; 9 list.add(lists.get(i)); 10 } 11 } 12 if(k == 0) return null; 13 if(k == 1) return list.get(0); 14 ListNode[] heap = new ListNode[k]; 15 for(int i = 0 ; i < k ; heap[i] = list.get(i),i++); 16 for(int i = k / 2 - 1; i >= 0; i--){ 17 adjustHeap(heap, k, i); 18 } 19 ListNode result = new ListNode(0); 20 ListNode tail = result; 21 while(true){ 22 if(heap[0] == null){ 23 heap[0] = heap[k - 1]; 24 k--; 25 } 26 adjustHeap(heap, k, 0); 27 tail.next = heap[0]; 28 if(k == 0) break; 29 heap[0] = heap[0].next; 30 tail = tail.next; 31 } 32 return result.next; 33 } 34 private void adjustHeap(ListNode[] heap,int size,int i){ 35 while( 2 * i + 1 < size ){ 36 ListNode left = heap[2 * i + 1]; 37 if(left == null) return; 38 if(2 * i + 2 < size){ 39 ListNode right = heap[2 * i + 2]; 40 if(right.val <= left.val && right.val < heap[i].val){ 41 ListNode tem = right; 42 heap[2 * i + 2] = heap[i]; 43 heap[i] = tem; 44 i = 2 * i + 2; 45 }else if(left.val <= right.val && left.val < heap[i].val){ 46 ListNode tem = left; 47 heap[2 * i + 1] = heap[i]; 48 heap[i] = tem; 49 i = 2 * i + 1; 50 }else return; 51 }else{ 52 if(left.val < heap[i].val){ 53 ListNode tem = left; 54 heap[2 * i + 1] = heap[i]; 55 heap[i] = tem; 56 } 57 return; 58 } 59 } 60 } 61 62 }
第二遍:
使用PriorityQueue的算法更简单一点,不过需要注意要定义比较器
代码如下:
1 public class Solution { 2 public ListNode mergeKLists(List<ListNode> lists) { 3 if(lists == null || lists.size() == 0) return null; 4 Queue<ListNode> pq = new PriorityQueue<ListNode>(20,new Comparator<ListNode>(){ 5 @Override 6 public int compare(ListNode a,ListNode b){ 7 return a.val - b.val; 8 } 9 }); 10 ListNode newHead = new ListNode(0); 11 ListNode tail = newHead; 12 for(ListNode head : lists){ 13 if(head != null) pq.offer(head); 14 } 15 while(!pq.isEmpty()){ 16 ListNode node = pq.poll(); 17 tail.next = node; 18 if(node.next != null) pq.offer(node.next); 19 node.next = null; 20 tail = node; 21 } 22 return newHead.next; 23 } 24 }
参考资料: