「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」
题目
给你链表的头结点 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 = []
输出:[]
提示:
链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105
进阶: 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
来源:力扣(LeetCode)leetcode-cn.com/problems/so…
解题思路
如果需要把时间复杂度控制在 O(n log n) 下,很容易就会想到二路归并排序。
二路归并排序的实现方式:
- 链表查找中间节点:通过双指针遍历链表,当快指针走出链表时,慢指针的当前位置就是链表的中间节点;
- 找到中间节点后,把中间节点的下个节点存起来当作右子链表的头节点,同时把中间节点和后面的节点断开;
- 分别对左子链接(头节点)和右子链接(上一步存起来的头节点)递归排序;
- 递归结束条件:头节点的 next 为 null;
- 合并左右两个子链表;
代码实现
var sortList = function (head) {
//head.next 为空时,递归结束
if (head === null || head.next === null) return head
let fast = head.next
let slow = head
//找到链表的中间节点
while (fast && fast.next) {
slow = slow.next
fast = fast.next.next
}
const tmp = slow.next
slow.next = null //从中间断开
//递归排序左边子链表
let left = sortList(head)
//递归排序右边子链表
let right = sortList(tmp)
let curr = new ListNode()
const ans = curr
while (left && right) {
if (left.val <= right.val) {
//左链表表头节点小于等于右链表表头节点,把左链表头节点加入新链表
//左链表后移
curr.next = left
left = left.next
} else {
//右链表表头节点大于左链表表头节点,把右链表头节点加入新链表
//右节点后移
curr.next = right
right = right.next
}
//新链表当前节点后移
curr = curr.next
}
//把左边或右边剩余的部分加到链表中
curr.next = left ? left : right
return ans.next
};
如有错误欢迎指出,欢迎一起讨论!