题目大意:合并多个有序链表成为一个有序单链表。21题是合并两个有序链表。例子如下:
法一(借鉴):利用优先队列构造最小堆,首先将k个链表的首结点入堆,构建初始堆,然后取出堆顶元素,即最小的元素,加入结果链表中,然后将堆顶元素的下一个节点加入堆中,再取出堆顶元素,继续操作,这样就保证了每次都是取最小元素入堆。代码如下(耗时11ms):
1 public ListNode mergeKLists(ListNode[] lists) { 2 if(lists.length == 0) { 3 return null; 4 } 5 //定义最小堆 6 PriorityQueue<ListNode> q = new PriorityQueue<ListNode>(11, new Comparator<ListNode>() { 7 public int compare(ListNode n1, ListNode n2) { 8 return n1.val - n2.val; 9 } 10 }); 11 //初始化最小堆,将k个链表的首节点放入堆中 12 for(int i = 0; i < lists.length; i++) { 13 if(lists[i] != null) { 14 q.offer(lists[i]); 15 } 16 } 17 ListNode head = new ListNode(0), cur = head; 18 while(!q.isEmpty()) { 19 //取出堆顶元素尾插,即将堆中最小值插入结果链表中 20 cur.next = q.poll(); 21 cur = cur.next; 22 //将堆顶元素的下一个元素加入堆中,即原链表中的下一个元素 23 if(cur.next != null) { 24 q.offer(cur.next); 25 } 26 } 27 return head.next; 28 }
法二(借鉴):分治。每次归并n/2个链表,如果有6个链表,归并1,4和2,5和3,6。这样最后得到的结果链表一定在1中。当然也可以逐一归并,即1,2和3,4和5,6。是一样的。代码如下(耗时9ms):
1 public ListNode mergeKLists(ListNode[] lists) { 2 if(lists.length == 0) { 3 return null; 4 } 5 int n = lists.length; 6 while(n > 1) { 7 //每次都取一半进行归并 8 int mid = (n + 1) / 2; 9 //如果是6个链表,则归并1,4和2,5和3,6,如此归并最后得到的结果链表一定在1中 10 for(int i = 0; i < n / 2; i++) { 11 lists[i] = mergeLists(lists[i], lists[mid + i]); 12 } 13 n = mid; 14 } 15 //返回最后的结果链表 16 return lists[0]; 17 } 18 //合并两个链表 19 public static ListNode mergeLists(ListNode l1, ListNode l2) { 20 ListNode head = new ListNode(0), cur = head; 21 while(l1 != null && l2 != null) { 22 if(l1.val < l2.val) { 23 cur.next = l1; 24 l1 = l1.next; 25 } 26 else { 27 cur.next = l2; 28 l2 = l2.next; 29 } 30 cur = cur.next; 31 } 32 if(l1 != null) { 33 cur.next = l1; 34 } 35 if(l2 != null) { 36 cur.next = l2; 37 } 38 return head.next; 39 }