目录
描述
示例1
示例2
思路:
代码:
描述
合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。
示例1
输入:[{1,2,3},{4,5,6,7}]
返回值:{1,2,3,4,5,6,7}
示例2
输入:[{1,2},{1,4,5},{6}]
返回值:{1,1,2,4,5,6}
思路:
按照之前的合并两个有序的链表的话,我们两个两个合并会做很多重复的工作,比如说,之前已经排好的顺序我们合并的时候会再次比较一遍,这样的话就会很繁琐
归并排序是什么?简单来说就是将一个数组每次划分成等长的两部分,对两部分进行排序即是子问题。对子问题继续划分,直到子问题只有1个元素。还原的时候呢,将每个子问题和它相邻的另一个子问题利用上述双指针的方式,1个与1个合并成2个,2个与2个合并成4个,因为这每个单独的子问题合并好的都是有序的,直到合并成原本长度的数组
对于这k个链表,就相当于上述合并阶段的k个子问题,需要划分为链表数量更少的子问题,直到每一组合并时是两两合并,然后继续往上合并,这个过程基于递归:
- 终止条件: 划分的时候直到左右区间相等或左边大于右边。
- 返回值: 每级返回已经合并好的子问题链表。
- 本级任务: 对半划分,将划分后的子问题合并成新的链表。
具体做法:
- step 1:从链表数组的首和尾开始,每次划分从中间开始划分,划分成两半,得到左边n/2n/2n/2个链表和右边n/2n/2n/2个链表。
- step 2:继续不断递归划分,直到每部分链表数为1.
- step 3:将划分好的相邻两部分链表,按照两个有序链表合并的方式合并,合并好的两部分继续往上合并,直到最终合并成一个链表。
图示:
代码:
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
return divideList(lists, 0, lists.size()-1);
}
public ListNode divideList(ArrayList<ListNode> lists, int l, int r) {
if (l > r) {
return null;
}
if (l == r) {
return lists.get(l);
}
int mid = (l + r) / 2;
return mergeTwoNode(divideList(lists, l, mid), divideList(lists, mid + 1, r));
}
public ListNode mergeTwoNode(ListNode n1, ListNode n2) {
if (n1 == null || n2 == null) {
return n1 != null ? n1 : n2;
}
if (n1.val < n2.val) {
n1.next = mergeTwoNode(n1.next, n2);
return n1;
} else {
n2.next = mergeTwoNode(n2.next, n1);
return n2;
}
}
}