1. Divide And Conquer
a. 算法解释
对于这道题,我们可以通过分治法把n个ListNode的合并简化成2个ListNode的合并问题。
整个算法分为两个阶段,一个是如何按顺序遍历各个ListNode进行合理的两两合并,另一个是如何实现2个ListNode节点的合并问题。
- 遍历lists中的各个ListNode节点
引入interval间距的概念对链表进行合理的两两配对合并,每次循环间距都会扩大一倍直到间距大于lists的实际长度。当用for循环进行遍历时,我们需要根据间距intervals,跳过一些元素。下面我们对含有7个链表的lists进行简单的分析。
如图,各个链表进行两两配对进行合并,但当链表的数量为奇数时,会多出一个链表无法进行配对,如果我们遍历到该链表时,程序会报错,因为我们无法访问到该元素间距之后的元素。所以我们的遍历结束条件应为length - interval。并且我们需要进行间隔访问,索引的递增量必须为2 * interval,这样我们才能合理的跳过所配对的元素。
b. 复杂度分析
时间复杂度: O(Nlogk) K为lists中链表的数量
空间复杂度: O(1)
c. 参考代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
// simplify the problme into small problem
// conquer and divide
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) return null;
if (lists.length == 1) return lists[0];
// to merge list
int interval = 1;
int length = lists.length;
while (interval < length){
// skip the interval element
for (int i = 0; i < length - interval; i+=interval*2){
// combine two list
// increase the interval to change the list
lists[i] = mergeTwoLists(lists[i], lists[i+interval]);
}
interval *=2;
}
return lists[0];
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2){
ListNode tempNode = new ListNode(0);
// save the address of headnode
ListNode headNode = tempNode;
while(l1 != null && l2 != null){
if (l1.val <= l2.val){
tempNode.next = l1;
l1 = l1.next;
}else{
tempNode.next = l2;
l2 = l2.next;
}
tempNode = tempNode.next;
}
while(l1 != null){
tempNode.next = l1;
l1 = l1.next;
tempNode = tempNode.next;
}
while(l2 != null){
tempNode.next = l2;
l2 = l2.next;
tempNode = tempNode.next;
}
return headNode.next;
}
}
参考文档
leetcode solution — Merge k Sorted Lists