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
解題思路:
本題還是有點意思的,雖然只是看上去只是鏈表排序,但是要求時間複雜度O(n log n),空間複雜度O(1)。需要用到歸併排序。一般而言,歸併排序的空間複雜度爲n,但是本題爲鏈表,可以控制在常數級別。
在做本題之前,建議先看看這篇https://blog.csdn.net/qq_41562704/article/details/89429773如何合併兩個有序的鏈表。
歸併排序先將節點每兩個一組排序,再將每兩個小組(即4個節點)排序;但是本題並非數組存儲,無法直接到達下一組的起點,所以本題需要用遞歸,將鏈表平均分爲兩半,直到只有單個節點,將兩半鏈表合併(用鏈接中的方法),根據遞歸性質,合併的時候,兩半的鏈表都各自排序好的。另外還有一個問題,如何找到鏈表的中點,這裏用到快慢指針法,在判斷鏈表中是否有環的時候常用到。
class Solution {
public:
ListNode* sortList(ListNode* head) {
return head == nullptr ? head : mergeSort(head);
}
private:
ListNode* mergeSort(ListNode* node){
if(node->next == nullptr)
return node;
ListNode *fast = node, *slow = node, *mid;
while(fast != nullptr && fast->next != nullptr){
mid = slow;
slow = slow->next;
fast = fast->next->next;
}
mid->next = nullptr;
ListNode* L = mergeSort(node);
ListNode* R = mergeSort(slow);
return merge(L, R);
}
ListNode* merge(ListNode* L, ListNode* R){
if(L == nullptr)
return R;
if(R == nullptr)
return L;
if(L->val <= R->val){
L->next = merge(L->next, R);
return L;
}
else{
R->next = merge(L, R->next);
return R;
}
}
};