1. 程式人生 > >LeetCode--148. Sort List

LeetCode--148. Sort List

題目連結:https://leetcode.com/problems/sort-list/

要求在O(nlogn)的時間複雜度和O(1)空間複雜度下完成排序,這個首先想到的是快排 、歸併、堆排序這類O(nlogn)的時間複雜度的演算法,又要求在O(1)空間複雜度下完成這個操作,那堆排序肯定是不行的。快排的遞迴中的合併兩個子陣列時是基於兩個子陣列與哨兵進行比較來實現的,嚴格依賴陣列下標,用在連結串列上可能十分吃力。只能歸併試試。

程式碼與陣列的歸併排序類似,歸併排序可以參考這一篇詳細理解https://blog.csdn.net/To_be_to_thought/article/details/83988767

,都是先對整個連結串列進行切分直到子連結串列大小為1,然後對相鄰兩有序子連結串列進行合併,對了合併兩個有序連結串列為一個有序連結串列的題目我們原來做過,請參見https://blog.csdn.net/To_be_to_thought/article/details/85057542

關鍵是如何切分呢,這裡採用快慢指標法將整個連結串列且分為兩個長度基本相等的子連結串列,切分程式碼如下:

public ListNode sortList(ListNode head) {
        
        if(head==null || head.next==null)
            return head;
        //子連結串列長度為1就return

        ListNode pFast=head,pSlow=head;
        while(pFast.next!=null && pFast.next.next!=null)
        {
            pSlow=pSlow.next;
            pFast=pFast.next.next;
        }
        ListNode mid=pSlow.next;
        pSlow.next=null;
        
        ListNode half1=sortList(head);
        ListNode half2=sortList(mid);
        //相鄰兩個有序子連結串列進行合併
        ListNode sorted=mergeTwoLists(half1,half2);
        return sorted;
        
    }

快慢指標的用法可以參考這一篇:https://blog.csdn.net/To_be_to_thought/article/details/83958314

整個程式碼效能還不錯,如下:

class Solution {
    public ListNode sortList(ListNode head) {
        
        if(head==null || head.next==null)
            return head;
        ListNode pFast=head,pSlow=head;
        while(pFast.next!=null && pFast.next.next!=null)
        {
            pSlow=pSlow.next;
            pFast=pFast.next.next;
        }
        ListNode mid=pSlow.next;
        pSlow.next=null;
        
        ListNode half1=sortList(head);
        ListNode half2=sortList(mid);
        
        ListNode sorted=mergeTwoLists(half1,half2);
        return sorted;
        
    }
    
    public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null)
            return l2;
        if(l2==null)
            return l1;
        ListNode head=null;
        if(l1.val<l2.val)
        {
            head=l1;
            l1=l1.next;
        }    
        else
        {
            head=l2;
            l2=l2.next;
        }
            
        ListNode p=head;
        
        while(l1!=null && l2!=null)
        {
            if(l1.val<l2.val)
            {
                p.next=l1;
                p=l1;
                l1=l1.next;
            }
            else
            {
                p.next=l2;
                p=l2;
                l2=l2.next;
            }
        }
        if(l1==null)
            p.next=l2;
        if(l2==null)
            p.next=l1;
        return head;
    }
}

嚴格來說,遞迴的空間複雜度為O(logn),但在LeetCode裡不把隱式遞迴的空間開銷算進來,這是在鼓勵用遞迴這種簡潔雋永的方式來解題,但在實際開發中還是要避免使用。