题目和LeetCode(21)里merge two sorted List要求差不多,现在只是从2两个list变成了k个list。
看到这个题,第一个反应是用一个heap(最大堆)把k个list里面的数存起来,然后一个一个poll出来生成一个新的list。遍历所有list要O(n),再堆里面插入元素,需要O(log(n))的时间,再生成新的List需要O(n),所以平均时间为O(nlog(n) + n),
代码如下:
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 public class Solution { 10 public ListNode mergeKLists(ListNode[] lists) { 11 ListNode dumpNode = new ListNode(0); 12 Queue<Integer> heap = new PriorityQueue<Integer>(); 13 //把所有元素都放到heap里面。 14 for (ListNode head : lists) { 15 while (head != null) { 16 heap.offer(head.val); 17 head = head.next; 18 } 19 } 20 ListNode curr = dumpNode; 21 //生成新的list 22 while (!heap.isEmpty()) { 23 curr.next = new ListNode(heap.poll()); 24 curr = curr.next; 25 } 26 return dumpNode.next; 27 } 28 }
这样做其实非常简单,但是鉴于这道题是一道hard的题,我估计这样做并不能够得到面试官的认可。首先,它并没有利用到每个list sorted的这一个性质,第二个,时间上也可以有更快的方法。
怎么做呢?那就是利用了归并排序的特点,divide and conquer(分治)。首先是把相邻的两个list两两配对,利用LeetCode 21 merge two sorted list的方法,分别把它们merge起来,然后继续两两配对,知道merge到一个list为止。
代码如下:
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 public class Solution { 10 public ListNode mergeKLists(ListNode[] lists) { 11 ListNode res = mergeKListsHelper(lists,0,lists.length - 1); 12 return res; 13 } 14 15 private ListNode mergeKListsHelper(ListNode[] lists, int left, int right) { 16 //返回条件的三种情况。 17 if (left > right) return null; 18 //没有配对上的list 19 if (left == right) return lists[left]; 20 //当left和right相差一个时,把它们merge起来。 21 if (left + 1 == right) return mergeSortedList(lists[left],lists[right]); 22 //分治,对于每一堆list,中间分开,左右各自合并,最后再merge 23 int mid = (left + right) / 2; 24 ListNode leftNode = mergeKListsHelper(lists, left, mid-1); 25 ListNode rightNode = mergeKListsHelper(lists, mid, right); 26 return mergeSortedList(leftNode, rightNode); 27 } 28 29 //merge两个list。和Leetcode 21一样。 30 private ListNode mergeSortedList(ListNode l1, ListNode l2) { 31 ListNode dumpNode = new ListNode(0); 32 ListNode curr = dumpNode; 33 while (l1 != null && l2 != null) { 34 if (l1.val < l2.val) { 35 curr.next = new ListNode(l1.val); 36 l1 = l1.next; 37 } 38 else { 39 curr.next = new ListNode(l2.val); 40 l2 = l2.next; 41 } 42 curr = curr.next; 43 } 44 45 while (l1 != null) { 46 curr.next = new ListNode(l1.val); 47 l1 = l1.next; 48 curr = curr.next; 49 } 50 51 while (l2 != null) { 52 curr.next = new ListNode(l2.val); 53 l2 = l2.next; 54 curr = curr.next; 55 } 56 57 return dumpNode.next; 58 } 59 }