1. 程式人生 > >[C++]LeetCode: 125 Sort List (歸併排序連結串列)

[C++]LeetCode: 125 Sort List (歸併排序連結串列)

題目:Sort a linked list in O(n log n) time using constant space complexity.

思路:題目要求我們使用常數空間複雜度,時間複雜度為O(nlog(n)). 滿足這個時間複雜度的有快速排序,歸併排序,堆排序。插入排序時間複雜度為O(n^2). 雙向連結串列用快排比較合適,堆排序也可用於連結串列,單項鍊表適合於歸併排序。我們就用歸併排序的思想來完成連結串列的排序。

首先是用快慢雙指標找到連結串列中間的位置,然後分成前後端分別遞迴的歸併排序,最後合併。

Attention:

1. 快慢指標找中間節點的方法,是常用方法,要熟練使用。

//將連結串列分成前後兩部分 雙指標找到中間節點
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast->next != NULL && fast->next->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
2. 連結串列的資料結構是如何實現歸併的方法的。定義一個合併後的連結串列,然後把合適的節點放進去。思想和陣列是一樣的,只是連結串列操作不一樣。

複雜度:如果這裡我們考慮遞迴的棧空間的話,空間複雜度是O(lg(n))

AC Code:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *sortList(ListNode *head) {
        if(head == NULL || head->next == NULL) return head;
        //將連結串列分成前後兩部分 雙指標找到中間節點
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast->next != NULL && fast->next->next != NULL)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* head2 = slow->next;
        slow->next = NULL;
        ListNode* head1 = head;
        head1 = sortList(head1);   //前半段歸併排序
        head2 = sortList(head2);   //後半段歸併排序
        return merge(head1, head2);
    }

private:
    ListNode* merge(ListNode* h1, ListNode* h2)
    {
        ListNode* dummyhead = new ListNode(0);
        ListNode* mlist = dummyhead;
        
        while(h1 != NULL && h2 != NULL)
        {
            if(h1->val <= h2->val)
            {
                mlist->next = h1;
                h1 = h1->next;
            }
            else
            {
                mlist->next = h2;
                h2 = h2->next;
            }
            mlist = mlist->next;
        }
        if(h1 != NULL)
        {
            mlist->next = h1;
        }
        if(h2 != NULL)
        {
            mlist->next = h2;
        }
        return dummyhead->next;
    }
};

我們也可以不使用遞迴的方法,自底向上的非遞迴版本的歸併排序,空間複雜度就是常數了。可以看下這篇博文:sort list.
排序是面試中很常見和基礎的一個主題,我們需要對各種常見的排序演算法要熟悉。尤其是演算法的原理,很多題目雖然沒有直接考察排序的實現,但是會用到其中的思想,比如經典的topK問題,用到了快排的原理。這篇文章中有提到,可以看看:Median of Two Sorted Arrays.所以我們應該要更加註重排序演算法的原理。