835 字
4 分钟
排序链表

题目描述
给你链表的头结点 head
,请将其按 升序 排列并返回 排序后的链表 。
解题思路
- 归并排序框架:
- 使用快慢指针找到链表中点
- 递归排序左半部分链表
- 递归排序右半部分链表
- 合并两个有序链表
- 迭代优化:
- 自底向上归并,避免递归栈空间
- 按子链表长度倍增合并
- 关键操作:
- 链表分割时需断开中点连接
- 合并过程使用哑节点简化操作
- 空间控制:
- 迭代法实现常数空间复杂度
关键洞察
- 链表特性利用:
- 归并排序天然适合链表结构
- 合并操作无需额外空间
- 中点定位技巧:
- 快指针走2步,慢指针走1步
- 慢指针停在中点前驱位置
- 递归终止条件:
- 空链表或单节点链表已有序
- 迭代步进控制:
- 子链表长度从1开始倍增
- 每次遍历完成整轮合并
复杂度分析
方法 | 时间复杂度 | 空间复杂度 |
---|---|---|
递归法 | O(n log n) | O(log n) (递归栈) |
迭代法 | O(n log n) | O(1) |
代码实现
递归法
/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } *//** * @param {ListNode} head * @return {ListNode} */var sortList = function (head) {
const toSortList = (head, tail) => {
if (!head) return head; if (head.next === tail) { head.next = null; return head; }
let fast = slow = head;
while (fast !== tail) { slow = slow.next; fast = fast.next; if (fast !== tail) { fast = fast.next; } }
let mid = slow; return merge(toSortList(head, mid), toSortList(mid, tail)) }
const merge = (head1, head2) => { const dummyHead = new ListNode(0); let temp = dummyHead, temp1 = head1, temp2 = head2;
while (temp1 !== null && temp2 !== null) { if (temp1.val <= temp2.val) { temp.next = temp1; temp1 = temp1.next } else { temp.next = temp2; temp2 = temp2.next }
temp = temp.next; }
if (temp1 !== null) { temp.next = temp1 } else if (temp2 !== null) { temp.next = temp2; }
return dummyHead.next; }
return toSortList(head, null);};
迭代法
/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } *//** * @param {ListNode} head * @return {ListNode} */const sortList = (head) => { // 边界处理 if (!head || !head.next) return head;
// 获取链表长度 let n = 0, cur = head; while (cur) { n++; cur = cur.next; }
const dummy = new ListNode(-1, head);
// 子链表长度从1开始倍增 for (let size = 1; size < n; size *= 2) { let prev = dummy; let cur = dummy.next;
while (cur) { // 获取左子链表 const left = cur; const right = split(left, size); cur = split(right, size); // 剩余部分
// 合并左右子链表 prev.next = merge(left, right);
// 移动prev到合并后链表的末尾 while (prev.next) { prev = prev.next; } } }
return dummy.next;};
// 合并两个有序链表const merge = (l1, l2) => { const dummy = new ListNode(-1); let cur = dummy;
while (l1 && 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 || l2; return dummy.next;};
// 分割链表:返回后半部分头节点const split = (head, size) => { if (!head) return null;
// 移动size-1步找到分割点 for (let i = 1; i < size && head.next; i++) { head = head.next; }
const nextHead = head.next; head.next = null; // 断开连接 return nextHead;};