在 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;
}
}
};