leetcode_效率題解_148. Sort List_(鏈表歸併排序)

相關題解:
leetcode_效率題解_[python/C++]_147. Insertion Sort List(鏈表插入排序)

題目鏈接
【題目】
Sort a linked list in O(n log n) time using constant space complexity.
這裏寫圖片描述
【分析】
O(nlogn)的複雜度我們很顯然想到歸併排序,快速排序


記得大一的時候寫鏈表排序的題都是先轉成數組或者vector然後再進行排序,貼出來以便大家熟悉一下數組的歸併排序

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if( head == NULL ) return head;
        vector<int> vec;
        while( head != NULL ){
            vec.push_back(head->val);
            head = head->next;
        }
        int size = vec.size();
        merge_sort( vec , 0 , size - 1 );
        ListNode * List = new ListNode(vec[0]);
        ListNode * ans = List;
        for( int i = 1 ; i < size ; i ++ ){
            ListNode * temp = new ListNode(vec[i]);
            ans->next = temp;
            ans = ans->next;
        }
        return List;

    }
    void merge( vector<int>& a , int low , int mid , int high ){
        vector<int> temp( high - low + 1 , 0 );
        int i = low , j = mid+1 , m = mid , n = high , k = 0;
        while( i <= m && j <= n ){
            if( a[i] < a[j] ) temp[k++] = a[i++];
            else temp[k++] = a[j++];
        }
        while( i <= m ) temp[k++] = a[i++];
        while( j <= n ) temp[k++] = a[j++];
        for( int g = 0 ; g < k ; g ++ ) a[low+g] = temp[g];
    }
    void merge_sort( vector<int>& a , int low , int high ){
        if( low < high ){
            int mid = ( low + high )/2;
            merge_sort( a , low , mid );
            merge_sort( a , mid+1 , high );
            merge( a , low , mid , high );
        }
    }
};

然而效率是這樣的
這裏寫圖片描述
所以歸根到底我們還是得用指針來寫:
那重點在哪裏呢,在於如何找到一個鏈表的mid
這裏我用了下面一段代碼來找到分界點second_head

ListNode * slow = head;
        ListNode * fast = head->next;
        while(fast&&fast->next){
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode * second_head = slow->next;
        slow->next = NULL;

所以就簡單了:

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if( !head || !head->next ) return head;
        ListNode * slow = head;
        ListNode * fast = head->next;
        while(fast&&fast->next){
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode * second_head = slow->next;
        slow->next = NULL;
        return merge( sortList(head) , sortList(second_head) );
    }
    ListNode * merge( ListNode * left , ListNode * right ){
        ListNode * new_list = new ListNode(0);
        ListNode * temp = new_list;
        while( left && right ){
            if( left->val < right->val ){
                temp=temp->next = left;
                left = left->next;
            }
            else{
                temp = temp->next = right;
                right = right->next;
            }
        }
        if( left ) temp->next = left;
        else temp->next = right;
        return new_list->next;
    }

};

效率就是最前面的runtime
當然merge函數也可以這樣寫,效率也一樣的

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if( !head || !head->next ) return head;
        ListNode * slow = head;
        ListNode * fast = head->next;
        while(fast&&fast->next){
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode * second_head = slow->next;
        slow->next = NULL;
        return merge( sortList(head) , sortList(second_head) );
    }
    ListNode * merge( ListNode * left , ListNode * right ){
        ListNode * new_list = new ListNode(0);
        ListNode * temp = new_list;
        while( left || right ){
            if( left && ( !right || left->val < right->val ) ){
                temp = temp->next = left;
                left = left->next;
            }
            if( right && ( !left || left->val >= right->val ) ){
                temp = temp->next = right;
                right = right->next;
            }
        }
        temp->next = NULL;
        return new_list->next;
    }

};

至於快速排序,有點難想,就貼一個網上的寫法:

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        ListNode* tail;
        quickSort(head,tail);
        return head;
    }
private:
    void quickSort(ListNode* &head,ListNode* &tail){
        if(head==nullptr)
            return;
        ListNode left_head(-1),right_head(-1);
        ListNode *left_tail=&left_head,*right_tail=&right_head;
        ListNode *pivot_head=head,*pivot_tail=head,*now=head->next;
        int key=pivot_head->val;
        //paritition
        while(now!=nullptr){
            if(now->val < key){
                left_tail->next=now;
                left_tail=now;
            } else if(now->val > key){
                right_tail->next=now;
                right_tail=now;
            } else {
                pivot_tail->next=now;
                pivot_tail=now;
            }
            now=now->next;
        }

        //deal with end node
        right_tail->next=nullptr;
        left_tail->next=nullptr;
        pivot_tail->next=nullptr;

        quickSort(left_head.next,left_tail);
        quickSort(right_head.next,right_tail);
        //connect pivot,sorted left part,sorted right part
        if(left_head.next!=nullptr && right_tail!=&right_head){
            //left part and right part is not null
            //L->P->R
            left_tail->next=pivot_head;
            pivot_tail->next=right_head.next;
            head=left_head.next;
            tail=right_tail;

        } else if(left_head.next!=nullptr){
            //left part is not null but right part is null
            //L->P
            left_tail->next=pivot_head;
            head=left_head.next;
            tail=pivot_tail;
        } else if(right_tail!=&right_head){
            //right part is not null but left part is null
            //P->R
            pivot_tail->next=right_head.next;
            head=pivot_head;
            tail=right_tail;
        }
        //no need to deal with two null situation.
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章