1. 程式人生 > >Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexit

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexit

分治法 經典 下一個 complex 大小 結構 length lists class

題目:

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

這道題目在分布式系統中非常常見,來自不同client的sorted list要在central server上面merge起來。這個題目一般有兩種做法,下面一一介紹並且分析復雜度。 第一種做法比較容易想到,就是有點類似於MergeSort的思路,就是分治法,不了解MergeSort的朋友,請參見 歸並排序-維基百科,是一個比較經典的O(nlogn)的排序算法,還是比較重要的。思路是先分成兩個子任務,然後遞歸求子任務,最後回溯回來。這個題目也是這樣,先把k個list分成兩半,然後繼續劃分,知道剩下兩個list就合並起來,
合並時會用到 Merge Two Sorted Lists 這道題,不熟悉的朋友可以復習一下。代碼如下:
 
 1 public class Solution {
 2 
 3     public ListNode mergeKLists(ListNode[] lists) {
 4         if(lists.length == 0) {
 5             return null;
 6         }
 7 
 8         return merge(0, lists.length-1, lists);
 9     }
10 
11
public ListNode merge(int i, int j, ListNode[] lists) { 12 if(j < i) { 13 return null; 14 } 15 16 if(i == j) { 17 return lists[i]; 18 } 19 20 int mid = (j-i)>>1 + i; 21 ListNode l = merge(i, mid, lists);
22 ListNode r = merge(mid+1, j, lists); 23 24 ListNode dummy = new ListNode(0); 25 ListNode runner = dummy; 26 27 while(l != null && r != null) { 28 if(l.val > r.val) { 29 runner.next = r; 30 r = r.next; 31 runner = runner.next; 32 } else { 33 runner.next = l; 34 l = l.next; 35 runner = runner.next; 36 } 37 } 38 39 if(l == null && r == null) { 40 return dummy.next; 41 } 42 43 if(l == null) { 44 runner.next = r; 45 } else { 46 runner.next = l; 47 } 48 49 return dummy.next; 50 } 51 }

我們來分析一下上述算法的時間復雜度。假設總共有k個list,每個list的最大長度是n,那麽運行時間滿足遞推式T(k) = 2T(k/2)+O(n*k)。根據主定理,可以算出算法的總復雜度是O(nklogk)。如果不了解主定理的朋友,可以參見 主定理-維基百科 。空間復雜度的話是遞歸棧的大小O(logk)。

第二種方法:

這種方法用到了堆的數據結構,思路比較難想到,但是其實原理比較簡單。維護一個大小為k的堆,每次去堆頂的最小元素放到結果中,然後讀取該元素的下一個元素放入堆中,重新維護好。因為每個鏈表是有序的,每次又是去當前k個元素中最小的,所以當所有鏈表都讀完時結束,這個時候所有元素按從小到大放在結果鏈表中。這個算法每個元素要讀取一次,即是k*n次,然後每次讀取元素要把新元素插入堆中要logk的復雜度,所以總時間復雜度是O(nklogk)。空間復雜度是堆的大小,即為O(k)



 1 public class Solution {
 2 
 3     public ListNode mergeKLists(ArrayList<ListNode> lists) {
 4         PriorityQueue<ListNode> heap = new PriorityQueue<ListNode>(10, new Comparator<ListNode>(){
 5             public int compare(ListNode n1, ListNode n2) {
 6                 return n1.val - n2.val;
 7             }
 8         });
 9 
10         for(int i = 0; i < lists.size(); i++) {
11             ListNode node = lists.get(i);
12             if(node != null) {
13                 heap.offer(node);
14             }
15         }
16 
17         ListNode head = null;
18         ListNode pre = head;
19 
20         while(head.size() > 0) {
21             ListNode current = head.poll();
22             if(head == null) {
23                 head = null;
24                 pre = head;
25             } else {
26                 pre.next = current;
27             }
28 
29             pre = current;
30             if(current.next != null) {
31                 heap.offer(current.next);
32             }
33         }
34 
35         return head;
36     }
37 }

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexit