[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

链表长度范围是[0, 5 * 104], 节点值范围是-105 <= Node.val <= 105

思路:

这是一道中等难度的题目。一个简单的思路是,把整个链表塞进一个vecor<int>并用STL的sort来排序,完成之后再用指针把每个元素链接起来。但这个思路只是调用了sort函数。对于这道题,至少应该实际写一下排序的算法。(事实上这道题这么做的话会超时)

看到链表排序这一主题,意识到这不是线性表。快速排序和堆排序并不适合链表,快速排序需要快速定位pivot而堆排序需要顺序地表示一个堆。而基数排序就更不适合该场景了——基数排序适用于多关键字的场景。因此插入排序/交换排序/归并排序比较适合链表结构,插入排序达不到O(n logn),交换排序也是如此,所以要满足O(nlogn) 复杂度,只能使用归并排序

AC代码:

不能行的插入排序,贼慢,差一点就超时了:

/**
 * 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* sortedHead = new ListNode(0);
        sortedHead->next = head;
        
        ListNode* lastSorted = head;
        ListNode* curr = head->next;
        
        while (curr) {
            if (lastSorted->val <= curr->val) {
                lastSorted = lastSorted->next;
            } else {
                ListNode* prev = sortedHead;
                while (prev->next->val <= curr->val) {
                    prev = prev->next;
                }
                lastSorted->next = curr->next;
                curr->next = prev->next;
                prev->next = curr;
            }
            curr = lastSorted->next;
        }
        
        ListNode* result = sortedHead->next;
        delete sortedHead;
        return result;
    }
};Code language: C++ (cpp)

能行的归并排序:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (!head || !head->next) return head;
        
        ListNode* mid = findMiddle(head);
        ListNode* rightHead = mid->next;
        mid->next = nullptr;

        ListNode* left = sortList(head);
        ListNode* right = sortList(rightHead);
        
        return merge(left, right);
    }
private:
    ListNode* findMiddle(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head->next;
        
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
    

    ListNode* merge(ListNode* l1, ListNode* l2) {
        ListNode dummy(0);
        ListNode* tail = &dummy;
        
        while (l1 && l2) {
            if (l1->val <= l2->val) {
                tail->next = l1;
                l1 = l1->next;
            } else {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }
        
        tail->next = l1 ? l1 : l2;
        return dummy.next;
    }
};Code language: C++ (cpp)