Leetcode 148.排序鏈表

在 O(n log n) 時間複雜度和常數級空間複雜度下,對鏈表進行排序。

示例 1:

輸入: 4->2->1->3
輸出: 1->2->3->4
示例 2:

輸入: -1->5->3->4->0
輸出: -1->0->3->4->5

思路:

利用歸併的思想,遞歸地將當前鏈表分爲兩段,然後merge,分兩段的方法是使用 fast-slow 法,用兩個指針,一個每次走兩步,一個走一步,知道快的走到了末尾,然後慢的所在位置就是中間位置,這樣就分成了兩段。merge時,把兩段頭部節點值比較,用一個 p 指向較小的,且記錄第一個節點,然後 兩段的頭一步一步向後走,p也一直向後走,總是指向較小節點,直至其中一個頭爲NULL,處理剩下的元素。最後返回記錄的頭即可

  • 知識點1:歸併排序的整體思想
  • 知識點2:找到一個鏈表的中間節點的方法
  • 知識點3:合併兩個已排好序的鏈表爲一個新的有序鏈表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    //知識點1:歸併排序的整體思想
    //知識點2:找到一個鏈表的中間節點的方法
    //知識點3:合併兩個已排好序的鏈表爲一個新的有序鏈表
    ListNode* sortList(ListNode* head) {
        return mergeSort(head);
    }
    ListNode* mergeSort(ListNode* node){
        if(!node||!node->next)return node;
        //快慢指針
        ListNode* fast=node;
        ListNode* slow=node;
        ListNode* breakN=node;//中間結點的前一個結點 即第一段鏈表的尾結點
        while(fast&&fast->next){
            fast=fast->next->next;
            breakN=slow;
            slow=slow->next;
        }
        breakN->next=nullptr;
        ListNode *l1=mergeSort(node);
        ListNode* l2=mergeSort(slow);
        return merge(l1,l2);
    }
    ListNode* merge(ListNode* l1,ListNode* l2){
        if(l1==nullptr)return l2;
        if(l2==nullptr)return l1;
        //分情況遞歸實現
        if(l1->val<=l2->val){
            l1->next=merge(l1->next,l2);
            return l1;
        }
        else{
            l2->next=merge(l2->next,l1);
            return l2;
        }
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章