23. Merge k Sorted Lists

輸入:k個有序鏈表lists
輸出:一個有序鏈表
規則:將這個k個有序鏈表合併成一個有序鏈表
分析:在鏈表中合併兩個有序鏈表爲一個有序鏈表是基本功。最開始的直覺是我們可以將lists[0]和lists[1]合併得到 result,result再和lists[2]合併,一直 到最後合併完成。這個每個節點 都要和其他鏈表中的一個節點比較,所以時間複雜度是O(k*n)。n是所有節點的個數總和。

	public ListNode mergeKLists(ListNode[] lists) {
		ListNode mergeHead = new ListNode(0);
		ListNode node = mergeHead;
		while(true){
			ListNode minHead = null;
            int idx = -1;
			for (int i=0;i<lists.length;i++) {
				if (lists[i] != null) {
					if(minHead == null || minHead.val> lists[i].val){
						minHead = lists[i];
                        idx = i;
					}
				}
			}
			if(minHead==null){
				break;
			}
            lists[idx] = lists[idx].next;
			node.next = new ListNode(minHead.val);
			node = node.next;
		}
		return mergeHead.next;
    }

分析2:可以使用堆排序解決上面的比較問題。在堆中維護的是每個鏈表 表頭元素。移除最小的節點,插入鏈表中的下一個節點。時間複雜度O(nlogk)。

	public ListNode mergeKLists(ListNode[] lists) {
        ListNode dummy =  new ListNode(-1);
        ListNode current = dummy;
        PriorityQueue<ListNode> heap = new PriorityQueue<ListNode>(new Comparator<ListNode>(){
            public int compare(ListNode i1,ListNode i2){
                return i1.val-i2.val;
            }
        });
        
        //把頭節點放進去
        for(ListNode node: lists){
            if(node!=null){
                heap.offer(node);
            }           
        }
        
        while(!heap.isEmpty()){
            ListNode node = heap.poll();
            if(node.next != null){
                heap.offer(node.next);
                
            } 
            current.next = node;
            current = current.next;
        }
        return dummy.next;
    }

分析3:使用分治法。先解決lists[0]和lists[1],lists[2]和lists[3]…,合併完成只剩下k2\dfrac{k}{2}。下一輪解決lists[0]和lists[2],lists[4]和lists[6]…,合併完成剩下k4\dfrac{k}{4}…一直到最後只剩下lists[0],就是結果。

	public ListNode mergeKLists(ListNode[] lists) {
        for(int interval =1 ;interval<lists.length; interval=interval*2){
            for(int j = 0;j+interval<lists.length;j = j + 2*interval){
                lists[j] = mergeTwoLists(lists[j],lists[j+interval]);
            }
        }
        return lists.length>0?lists[0]:null;
    }
    
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode currentNode = dummy;
        while(l1!=null  && l2!=null){
            if(l1.val > l2.val){
                currentNode.next = l2;
                l2 = l2.next;
            }else{
                currentNode.next = l1;
                l1 = l1.next;
            }
            currentNode = currentNode.next;
        }
        
        while(l1!=null){
            currentNode.next = l1;
            l1 = l1.next;
            currentNode = currentNode.next;
        }
        while(l2!=null){
            currentNode.next = l2;
            l2 = l2.next;
            currentNode = currentNode.next;
        }
        return dummy.next;
    }

複雜度分析。最外層循環有log2klog_2^k次。mergeTwoLists函數的時間複雜度是n=兩個列表節點個數的和。最後合起來是O(nlogk)。這裏的n是所有鏈表節點個數和。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章