题目地址:
https://www.lintcode.com/problem/merge-k-sorted-lists/description
给定一个list,里面的元素都是链表的头结点。每个链表都是单调增的。要求返回一个链表,其为这些链表的单调增的合并。
法1:用堆。开一个最小堆,然后将所有非null的头结点加进最小堆,接着每次都从堆顶取出一个链表节点,加到最终要返回的链表的尾部,然后将那个链表节点的next节点(非null的)加进最小堆,直到所有链表都遍历完为止。代码如下:
import java.util.List;
import java.util.PriorityQueue;
public class Solution {
/**
* @param lists: a list of ListNode
* @return: The head of one sorted list.
*/
public ListNode mergeKLists(List<ListNode> lists) {
// write your code here
ListNode dummy = new ListNode(0), cur = dummy;
PriorityQueue<ListNode> minHeap = new PriorityQueue<>((n1, n2) -> n1.val <= n2.val ? -1 : 1);
// 将所有非null的链表头结点加入最小堆中
for (ListNode head : lists) {
if (head != null) {
minHeap.offer(head);
}
}
while (!minHeap.isEmpty()) {
// 从堆顶取出节点,加到cur后面,同时cur后移一步
// 接着将取出的节点的非null的next节点加进最小堆
ListNode min = minHeap.poll();
cur.next = min;
cur = cur.next;
// 要判断非null
if (min.next != null) {
minHeap.offer(min.next);
}
}
return dummy.next;
}
}
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
}
}
时间复杂度 , 为链表总长度, 为链表的个数。空间复杂度 。
法2:分治法。如果lists长度为 ,那么直接返回这个链表就行了。否则的话,我们可以递归合并lists的左半部分链表和右半部分链表,最后再将两部分合并出来的两个链表最后做个合并即可。代码如下:
import java.util.List;
public class Solution {
/**
* @param lists: a list of ListNode
* @return: The head of one sorted list.
*/
public ListNode mergeKLists(List<ListNode> lists) {
// write your code here
return merge(lists, 0, lists.size() - 1);
}
// 作用是将lists从l到r部分的链表合并并返回
private ListNode merge(List<ListNode> lists, int l, int r) {
// 如果[l, r]里只有一个链表,则直接返回即可
if (l == r) {
return lists.get(l);
}
int m = l + (r - l >> 1);
// 递归合并左右两半部分
ListNode l1 = merge(lists, l, m);
ListNode l2 = merge(lists, m + 1, r);
// 开始合并l1和l2
ListNode dummy = new ListNode(0), cur = dummy;
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 dummy.next;
}
}
时间复杂度 ,空间复杂度 ,递归栈深度。
时间复杂度证明:
设时间消耗为
,那么:
得证。