LongDz 的数字文墨提案

148. 排序链表

4 min

题目

148. 排序链表 中等

解法:归并排序

思路

使用归并排序(分治法)对链表进行排序。通过快慢指针找到链表中点并分割,递归排序左右两部分后合并。

该方法正确性基于数学归纳法:当链表长度为0或1时自然有序;假设长度小于n的链表可排序,则对长度n的链表,分割后递归排序得到两个有序子链表,合并操作保持有序性,因此整个链表有序。

  • Step 1: 递归终止条件判断,若链表为空或只有一个节点则直接返回
  • Step 2: 使用快慢指针找到中点,并用prev指针记录中点前驱,将链表从中点断开
  • Step 3: 递归调用sortList分别排序左右两部分链表
  • Step 4: 调用merge函数合并两个已排序的子链表,返回合并后的头节点

复杂度

  • 时间复杂度: O(nlogn)O(n \log n)
  • 空间复杂度: O(logn)O(\log n)

代码

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        // 1. 递归终止条件
        if (head == nullptr || head->next == nullptr) {
            return head;
        }
        
        // 2. 找到中点并切断 (快慢指针)
        ListNode* prev = nullptr;
        ListNode* slow = head;
        ListNode* fast = head;
        
        while (fast != nullptr && fast->next != nullptr) {
            prev = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        
        // 将链表从中点断开
        prev->next = nullptr;
        
        // 3. 递归排序左右两部分
        ListNode* left = sortList(head);
        ListNode* right = sortList(slow);
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        // 1. 递归终止条件
        if (head == nullptr || head->next == nullptr) {
            return head;
        }
        
        // 2. 找到中点并切断 (快慢指针)
        ListNode* prev = nullptr;
        ListNode* slow = head;
        ListNode* fast = head;
        
        while (fast != nullptr && fast->next != nullptr) {
            prev = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        
        // 将链表从中点断开
        prev->next = nullptr;
        
        // 3. 递归排序左右两部分
        ListNode* left = sortList(head);
        ListNode* right = sortList(slow);
        
        // 4. 合并有序链表
        return merge(left, right);
    }

private:
    // 合并两个有序链表的辅助函数
    ListNode* merge(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode(0);
        ListNode* curr = dummy;
        
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val < l2->val) {
                curr->next = l1;
                l1 = l1->next;
            } else {
                curr->next = l2;
                l2 = l2->next;
            }
            curr = curr->next;
        }
        
        // 如果有一个链表还没走完,直接连接
        if (l1 != nullptr) curr->next = l1;
        if (l2 != nullptr) curr->next = l2;
        
        ListNode* head = dummy->next;
        delete dummy; // 释放内存
        return head;
    }
};