LeetCode:148. Sort List

一、問題描述

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

Example 1:

Input: 4->2->1->3
Output: 1->2->3->4

Example 2:

Input: -1->5->3->4->0
Output: -1->0->3->4->5

二、解題思路

單鏈表排序,其實就是將鏈表分割、然後合併。本質上還是Merge Two Sorted Lists,只不過之前由加上了歸併。

即:首先將鏈表分割成兩部分,然後對這兩部分進行排序。

鏈表數據的排序,時間複雜度控制在O(n log n)以內;空間複雜度爲常數,即O(1),不允許使用額外的空間。
首先是鏈表排序,不能像數組一樣隨意的訪問元素。歸併排序,時間複雜度爲O(n log n),滿足要求。空間複雜度,數組下的歸併排序爲O(n),即建立一個數組來存放排好的數。但在鏈表數據結構下,空間複雜度爲O(1)。因爲鏈表的節點從一開始給定後就不在變更,在排序過程中只是每個節點指向位置不同,即指針變化,而節點數不變。
歸併排序的核心思想就是:將原數組分開並遞歸此步驟,直到只有1個數時,開始比較排序併合並,即歸併。在鏈表中也類似,從head節點往後移動,找到中間節點並把鏈表一分爲二,遞歸此步驟。

具體是:設置快速指針fast和慢速指針slow,fast跑兩步slow跑一步,當fast跑的最後一個節點時,slow到達middle處。遞歸上述步驟,歸併時將節點重新排列。

注:鏈表,無new ListNode()代碼便不生成新節點,沒有額外空間。當使用ListNode* p創建新的鏈表指針時,並沒有建立新節點沒有增加額外空間,只是爲了改變已有節點的指向(空間複雜度爲O(1))。

三、代碼實現

/**
 * 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 || !head->next) return head;
       
        ListNode *slow = head, *fast = head, *pre = head;
        while (fast && fast->next)
        {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }//退出循環時,fast或fast->next = nullptr,slow指向中部位置
        pre->next = NULL; //將左右子鏈表斷開處
        return mergeTwoLists(sortList(head), sortList(slow)); //歸併左右子鏈表     
    }
private:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == NULL && l2 == NULL) return NULL;
        else if(l1 != NULL && l2 == NULL) return l1;
        else if(l1 == NULL && l2 != NULL) return l2;
        else {
            ListNode* preHead = new ListNode(0);
            //preHead 需要移動,因此使用resultHead來先保存下
            ListNode* resultHead = preHead;
            while( l1!=NULL && l2!=NULL){
                //同時不爲空,那就比較。然後將小的添加到preHead的尾部
                if(l1->val < l2->val){
                    preHead->next = l1;
                    preHead = preHead->next;
                    l1 = l1->next;
                }else{
                    preHead->next = l2;
                    preHead = preHead->next;
                    l2 = l2->next;
                }
                //while結束,說明有一個爲空了,那就把不爲空的直接加上
                if(l1!=NULL) preHead->next = l1;
                if(l2!=NULL) preHead->next = l2;
            }
            return resultHead->next;
        }
    }
};

 

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