23. 合并K个升序链表
题目描述 给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
输入输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1-> 4->5, 1-> 3->4, 2-> 6 ] 将它们合并到一个有序链表中得到。 1-> 1->2->3->4->4->5->6 输入:lists = [] 输出:[] 输入:lists = [[]] 输出:[]
基本思路 方法一:最愚蠢的方法 利用剑指 Offer 25. 合并两个排序的链表 全部两两合并得到结果
时间复杂度:假设每个链表的最长长度为n 第一次合并res长度为n
第二次2n
第i次in
则$O(n + (i-1)\times n) = O(in)$ 那么总的时间代价是$O(\sum_{i=1}^k(i \times n)) = O(\frac{(1+k)\times k}{2} \times n) = O(k^2n)$
最终可得 时复:$O(k^2n)$ 空复:$O(1)$
方法二:利用优先级队列 类似构建小顶堆的意思 保持队列头的结点数字最小
考虑优先队列中的元素不超过 $k$ 个,那么插入和删除的时间代价为 $O(logk)$,这里最多有 $kn$ 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 $O(kn \times \log k)$。
空复:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 $O(k)$。
1 2 3 4 运行45行之后 PriorityQueue: 三个节点 [1,1,2] dummy -> 1(p在这儿) if(p.next != null) queue.add(p.next); 运行后因为1(p) -> 4 重新将4丢入PriorityQueue的小根堆中
最终可得:时复:$O(kn \times \log k)$ 空复:$O(k)$
java实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Solution { public ListNode mergeKLists (ListNode[] lists) { int n = lists.length; ListNode res = null ; for (int i = 0 ; i < n; i++) { res = merge2Lists(res, lists[i]); } return res; } public ListNode merge2Lists (ListNode l1, ListNode l2) { ListNode res = new ListNode(0 ), cur = res; while (l1 != null && l2 != null ){ if (l1.val < l2.val){ cur.next = l1; l1 = l1.next; } else { cur.next = l2; l2 = l2.next; } cur = cur.next; } cur.next = l1 != null ? l1 : l2; return res.next; } } class Solution { public ListNode mergeKLists (ListNode[] lists) { if (lists == null || lists.length == 0 ) return null ; PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() { @Override public int compare (ListNode o1, ListNode o2) { if (o1.val < o2.val) return -1 ; else if (o1.val == o2.val) return 0 ; else return 1 ; } }); ListNode dummy = new ListNode(0 ); ListNode p = dummy; for (ListNode list:lists){ if (list != null ) queue.add(list); } while (!queue.isEmpty()){ p.next = queue.poll(); p = p.next; if (p.next != null ) queue.add(p.next); } return dummy.next; } }