1. 程式人生 > >LeetCode || Sort List

LeetCode || Sort List

Sort List  Sort a linked list in O(n log n) time using constant space complexity.         對一個連結串列進行排序,且時間複雜度要求為 O(n log n) ,空間複雜度為常量。一看到 O(n log n) 的排序,首先應該想到歸併排序和快速排序,但是通常我們使用這兩種排序方法時都是針對陣列的,現在是連結串列了。         歸併排序法:在動手之前一直覺得空間複雜度為常量不太可能,因為原來使用歸併時,都是 O(N)的,需要複製出相等的空間來進行賦值歸併。對於連結串列,實際上是可以實現常數空間佔用的。利用歸併的思想,遞迴地將當前連結串列分為兩段,然後merge,分兩段的方法是使用 fast-slow 法,用兩個指標,一個每次走兩步,一個走一步,知道快的走到了末尾,然後慢的所在位置就是中間位置,這樣就分成了兩段。merge時,把兩段頭部節點值比較,用一個 p 指向較小的,且記錄第一個節點,然後 兩段的頭一步一步向後走,p也一直向後走,總是指向較小節點,直至其中一個頭為NULL,處理剩下的元素。最後返回記錄的頭即可。程式碼如下:
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if(!head||!head->next)
            return head;
        return mergeSort(head);
    }
    ListNode * mergeSort(ListNode *head){
        if(!head||!head->next)   //just one element
            return head;
        ListNode *p=head, *q=head, *pre=NULL;
        while(q&&q->next!=NULL){
            q=q->next->next;
            pre=p;
            p=p->next;  //divide into two parts
        }
        pre->next=NULL;
        ListNode *lhalf=mergeSort(head);
        ListNode *rhalf=mergeSort(p);  //recursive
        return merge(lhalf, rhalf);   //merge
    }
    ListNode * merge(ListNode *lh, ListNode *rh){
        ListNode *temp=new ListNode(0);
        ListNode *p=temp;
        while(lh&&rh){
            if(lh->val<=rh->val){
                p->next=lh;
                lh=lh->next;
            }
            else{
                p->next=rh;
                rh=rh->next;
            }
            p=p->next;
        }
        if(!lh)
            p->next=rh;
        else
            p->next=lh;
        p=temp->next;
        temp->next=NULL;
        delete temp;
        return p;
    }
};


            快速排序:使用快排也行,就是每次利用頭節點作為基準,將小於它的交換到連結串列左側,大於它的放在右側,最後把它換到中間某個位置,然後遞迴處理左側和右側。但是相對於歸併來說,它的元素交換次數太多了,可能會超時。