Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
思路:
方法1, 利用merge two sorted list的方法来逐个merge, 假设K个list, 每个list的长度是n, 时间复杂度分析:
第一次merge lists[ 0 ] & lists[ 1 ], 时间复杂度是O(n + n),
然后用list[ 2] 来merge上一次得到的长度为 2n的list, O(2n + n)
.
.
.
最后一次merge是O( (k - 1)n + n)
可以看出这是一个等差数列, 2n, 3n, 4n, ... kn, 所以时间复杂度是O(nk^2), 但是这样太慢了, leetcode 会TLE
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode head = null;
for(int i = 0; i < lists.length; i++){
head = mergeTwoLists(lists[i], head);
}
return head;
}
private ListNode mergeTwoLists(ListNode A, ListNode B){
if(A == null && B == null){
return null;
}
if(A == null)
return B;
if(B == null)
return A;
ListNode dummy = new ListNode(0);
dummy.next = A;
ListNode pre = dummy;
while(A != null && B != null){
if(A.val < B.val){
A = A.next;
pre = pre.next;
}else{
ListNode next = B.next;
B.next = A;
pre.next = B;
B = next;
pre = pre.next;
}
}
// while(B != null){
// pre.next = B;
// B = B.next;
// pre = pre.next;
// }
if(B != null)
pre.next = B;
return dummy.next;
}
}
方法2:方法1的进阶,Divide and Conquer, 用merge sort的思想来解决问题 O(nklogk)
这里自己写的时候有个bug,
return mergeTwoLists(helper(lists, l, m), helper(lists, m + 1, r));
如果写成 helper(lists,l, m - 1), helper(lists, m , r), 则当 l = 0, r = 1, m = 0, helper(lists,m,r)还是helper(lists, 0, 1), 会一直递归直到stackOverflow
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0){
return null;
}
return helper(lists, 0, lists.length - 1);
}
private ListNode helper(ListNode[] lists, int l, int r){
if(l < r){
int m = l + (r - l) / 2;
return mergeTwoLists(helper(lists, l, m), helper(lists, m + 1, r)); //这里注意左右边界的取值, 如果 (l,m -1), (m, r), 会StackOverFlow
}
return lists[l];
}
private ListNode mergeTwoLists(ListNode A, ListNode B){
ListNode dummy = new ListNode(0);
dummy.next = A;
ListNode pre = dummy;
while(A != null && B != null){
if(A.val < B.val){
A = A.next;
pre = pre.next;
}else{
ListNode next = B.next;
B.next = A;
pre.next = B;
B = next;
pre = pre.next;
}
}
if(B != null)
pre.next = B;
return dummy.next;
}
}
方法3:用堆排序, 这里要自定义Comparator来排序ListNode,
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> pq = new PriorityQueue<ListNode>(10, new Comparator<ListNode>(){
@Override
public int compare(ListNode a, ListNode b){
return a.val - b.val;
}
});
for(int i = 0; i < lists.length; i++){
if(lists[i] != null)
pq.offer(lists[i]);
}
ListNode dummy = new ListNode(0);
ListNode pre = dummy;
while(!pq.isEmpty()){
ListNode cur = pq.poll();
if(cur.next != null){
pq.offer(cur.next);
}
pre.next = cur;
pre = pre.next;
}
return dummy.next;
}
}
方法2和3都是学习的code ganker大神的博客http://blog.youkuaiyun.com/linhuanmars/article/details/19899259