LeetCode148:链表排序终极解法

题目LeetCode148

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

示例

输入: head = 4,2,1,3

输出:1,2,3,4

此题如果用正常头插尾插法会超时,此题不做说明

Python解法

1.利用sort方法

此方法比较偷懒,可以看看,可以通过

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        arr = []
        p = head
        while p:
            arr.append(p.val)
            p = p.next
        arr.sort()
        p = head
        idx = 0
        while p:
            p.val = arr[idx]
            idx += 1
            p = p.next
        return head

2.归并+递归

python 复制代码
# 链表节点定义
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        # 递归终止:空链表 / 单节点链表天然有序
        if not head or not head.next:
            return head
        
        # 获取中点,拆分左右链表
        mid = self.findMiddle(head)
        right_head = mid.next
        mid.next = None  # 断开中点,分割左右
        
        # 递归分治排序左右子链表
        left_sorted = self.sortList(head)
        right_sorted = self.sortList(right_head)
        
        # 合并两个有序链表并返回
        return self.mergeTwoLists(left_sorted, right_sorted)
    
    # 快慢指针找左中点
    def findMiddle(self, head: ListNode) -> ListNode:
        slow = head
        fast = head.next  # fast起步在后,保证slow停在左中点
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        return slow
    
    # 合并两条有序单向链表
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = ListNode(-1)
        cur = dummy
        
        while l1 and l2:
            if l1.val < l2.val:
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
            cur = cur.next
        
        # 拼接剩余部分
        cur.next = l1 if l1 else l2
        return dummy.next

过程演示

Java解法

仅说明归并

代码示例

java 复制代码
public ListNode sortList(ListNode head) {
        // 递归终止条件:链表为空或只有一个节点
        if (head == null || head.next == null) {
            return head;
        }

        // 找到链表的中点
        ListNode mid = findMiddle(head);
        ListNode rightHead = mid.next; // 右半部分的头节点
        mid.next = null; // 断开链表

        // 递归排序左半部分和右半部分
        ListNode left = sortList(head);
        ListNode right = sortList(rightHead);

        // 合并两个有序链表
        return mergeTwoLists(left, right);
    }

    // 找到链表的中点(快慢指针法)
    private ListNode findMiddle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head.next; // fast 从 head.next 开始,确保 slow 指向中点或左中点
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    // 合并两个有序链表
    private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1); // 虚拟头节点
        ListNode curr = dummy;

        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                curr.next = l1;
                l1 = l1.next;
            } else {
                curr.next = l2;
                l2 = l2.next;
            }
            curr = curr.next;
        }

        // 将剩余的链表接上
        if (l1 != null) {
            curr.next = l1;
        }
        if (l2 != null) {
            curr.next = l2;
        }

        return dummy.next;
    }改为Python

C++解法(同Java)

代码示例

cpp 复制代码
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 == nullptr || head->next == nullptr) {
            return head;
        }

        // 找中点
        ListNode* mid = findMiddle(head);
        ListNode* rightHead = mid->next;
        mid->next = nullptr;

        // 递归排序左右两部分
        ListNode* left = sortList(head);
        ListNode* right = sortList(rightHead);

        // 合并有序链表
        return mergeTwoLists(left, right);
    }

private:
    // 快慢指针找左中点
    ListNode* findMiddle(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head->next;
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    // 合并两个有序链表,使用三目运算符简化收尾
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode dummy(-1);
        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;
        }

        // C++ 同样支持三目运算符
        curr->next = l1 ? l1 : l2;
        return dummy.next;
    }
};

注意Java的三目运算不能省略null,Java 中,对象引用不能直接当成布尔条件