Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
假设大家已经熟悉2个链表如何归并了。
在这里我讲介绍2种方法归并k个链表,这两种方法的复杂度都是O(nlogk) (n 为所有节点的个数)
第一种是基于分治思想的递归法。第二种是基于PriorityQueue的。
先来看第一种:基于分治的思想。
对于k个链表,把它们分成左一半,右一半。
假设左一半已经归并好了 left = merge(0, mid ),右一半也归并好了right = merge(mid + 1, k)。
那么现在需要做的就是再把 left 和 right 做2个链表归并的操作。
那么左一半如何具体进行归并呢? 可以再把它一切为2, 归并下去。
递归的停止条件就是,需要归并的链表数 <=2个。
这种方法的空间复杂度为O(1)。
代码写起来也很简洁,显示了递归的优美。
运行时间:
代码:
public ListNode mergeKLists(ListNode[] lists) {
return doMergeList(lists, 0, lists.length - 1);
}
public ListNode doMergeList(ListNode[] lists, int begin, int end) {
if (end < begin) {
return null;
}
if (end == begin) {
return lists[begin];
} else if (end - begin == 1) {
//do Merge two list
return mergeTwoLists(lists[begin], lists[end]);
} else {
int mid = (begin + end) / 2;
return mergeTwoLists(doMergeList(lists, begin, mid), doMergeList(lists, mid + 1, end));
}
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode fakeNode = new ListNode(-1), cur = fakeNode, curl1 = l1, curl2 = l2;
while (curl1 != null && curl2 != null) {
if (curl1.val < curl2.val) {
cur.next = curl1;
curl1 = curl1.next;
} else {
cur.next = curl2;
curl2 = curl2.next;
}
cur = cur.next;
}
cur.next = curl1 != null ? curl1 : curl2;
return fakeNode.next;
}
接下来看基于PriorityQueue的首先我们先明白一下什么是PriorityQueue。
它是一种特殊的queue,不同于先进先出,它里面的顺序是按照优先级排列的。
比如我有一个数组[1, 5, 6, 2, - 1]
如果把它放到PriorityQueue中去,那么在PriorityQueue中的排列就会变成[ - 1, 1, 2, 5, 6 ]
如果poll () 的话,会返回-1。
放进PriorityQueue中的变量,必须要是可以比较的。
我们想把ListNode的变量放进去。 (java的话,需要传给PriorityQueue的一个 ListNode 的 comparator )
具体的操作过程为:
假设我的lists值分别为:
node0 : 1 - > 2 -> 3
node1 : - 4 -> 4 -> 5
node2 : 0 -> 2
我将这3个node放到queue中。
此时queue长这样:
node1 : - 4 -> 4 -> 5
node0 : 1 - > 2 -> 3
此时:cur :- 4
node1.next != null, 将 4 - > 5 再放入queue
此时queue长这样:
1 - > 2 -> 3
4 -> 5
继续进行pop,弹出 0 - >2
此时:cur: -4 - > 0
将 2再放入queue。
...
直至queue为null,
此时,所有的都排好序了。
空间复杂度 O ( k )
运行时间:
代码:
public ListNode mergeByPriorityQueue(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 1;
}
return 0;
}
});
for (ListNode node : lists) {
if (node != null) {
queue.add(node);
}
}
ListNode fakeHead = new ListNode(-1), cur = fakeHead;
while (!queue.isEmpty()) {
ListNode node = queue.poll();
cur.next = node;
cur = cur.next;
if (node.next != null) {
queue.add(node.next);
}
}
return fakeHead.next;
}
参考资料:
https://leetcode.com/discuss/9279/a-java-solution-based-on-priority-queue