📘题目描述
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
示例 1:
输入:head = [4,2,1,3] 输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0] 输出:[-1,0,3,4,5]
示例 3:
输入:head = [] 输出:[]
💡解题思路:归并排序(自顶向下)
链表不能使用快速排序(因无法随机访问),推荐使用归并排序,尤其适合链表。
🧠为何选择归并排序?
-
快速排序需要随机访问,链表效率极低。
-
归并排序天然适配链表,拆分过程快慢指针即可完成。
-
时间复杂度 O(n log n),空间复杂度 O(log n)(递归栈)。
🚩算法流程(自顶向下归并):
-
找中点:使用快慢指针将链表一分为二。
-
递归排序:分别对左右链表递归调用
sortList
。 -
合并链表:调用
merge
合并两个已排序链表。
✅完整代码
class Solution:
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
# base case:空或仅一个节点,返回自己
if not head or not head.next:
return head
# 快慢指针找中点(slow为前半段尾部)
slow, fast = head, head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 断链,分成左右两部分
mid = slow.next
slow.next = None
# 递归排序左右子链表
left = self.sortList(head)
right = self.sortList(mid)
# 合并两个有序链表
return self.merge(left, right)
def merge(self, l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode(0)
tail = dummy
# 合并两个有序链表(类似合并k个链表模板)
while l1 and 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 if l1 else l2
return dummy.next
⏱️复杂度分析
类型 | 复杂度 | 说明 |
---|---|---|
时间复杂度 | O(n log n) | 每次划分为两半,递归深度为 log n,总共 O(n log n) |
空间复杂度 | O(log n) | 递归调用栈空间,非原地排序(迭代可优化到 O(1)) |
🖼️图示理解
链表 [4 → 2 → 1 → 3]
的归并排序过程:
step1: [4,2,1,3]
↓
step2: [4,2] 和 [1,3]
↓
step3: [4] 和 [2] → merge → [2,4]
[1] 和 [3] → merge → [1,3]
↓
step4: merge [2,4] 和 [1,3] → [1,2,3,4]
🧱常见易错点总结
易错点 | 说明 |
---|---|
快慢指针未正确断链 | slow.next = None 是断开关键 |
未处理 head is None 情况 | base case 条件不能漏 |
merge() 指针逻辑写错 | 注意 tail 的移动与连接顺序 |
使用快排/堆排 | 不适用于链表,性能/实现都不友好 |
🎯总结
-
归并排序是链表排序的最优解法。
-
借助快慢指针找中点,递归合并实现排序。