链表的归并排序
- 分割链表: 使用快慢指针找到链表的中点,将链表分割成两个部分。
- 递归排序: 对分割后的两个部分分别递归地进行排序。
- 合并有序链表: 使用归并的方法将两个有序链表合并成一个有序链表。
var sortList = function (head) {
// 终止递归的条件,当链表或者只有一个节点的时候,就是天然有序
if (!head || !head.next) return head
let slow = head, fast = head, pre = null
// 找到中点
while (fast && fast.next) {
pre = slow
slow = slow.next
fast = fast.next.next
}
pre.next = null
// 分解成最小的链表单位
let left = sortList(head)
let right = sortList(slow)
// 进行合并
return merge(left, right)
};
// 合并两个有序链表
var merge = function (l1, l2) {
let dummy = new ListNode(-1)
let current = dummy
while (l1 && l2) {
if (l1.val <= l2.val) {
current.next = l1
l1 = l1.next
} else {
current.next = l2
l2 = l2.next
}
current = current.next
}
current.next = l1 || l2
return dummy.next
}
⏱️ 时间 & 空间复杂度
- 时间复杂度:O(n log n),每次将链表对半分,分 log n 层,每层最多遍历 n 个节点。
- 空间复杂度:O(log n),递归栈的开销(不是原地排序,但符合题目对额外空间的要求)。