DAILY DOCDAILY DOC
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
Rust
Node
Notes
Ubuntu
Leetcode
  • it-tools
  • excalidraw
  • linux-command
  • Array

    • 数组
    • 二分查找
    • moveZeros
  • Dynamic-programming

    • 动态规划
  • 刷题指南
  • String

    • 字符串
  • bitwise-operator

    • 位运算符
  • heap
  • history

    • [1014] 最佳观光组合
    • [1022] 从根到叶的二进制数之和
    • [104] 二叉树的最大深度
    • [11] 盛最多水的容器
    • [110] 平衡二叉树
    • [1227] 飞机座位分配概率
    • [129] 求根节点到叶节点数字之和
    • [1306] 跳跃游戏 III
    • [148] 排序链表
    • 155.最小栈
    • [165] 比较版本号
    • 1763. 最长的美好子字符串
    • [1870] 准时到达的列车最小时速
    • [199] 二叉树的右视图
    • [21] 合并两个有序链表
    • 215.数组中的第 k 个最大元素
    • [2306] 公司命名
    • [234] 回文链表
    • [2516] 每种字符至少取 K 个
    • [316] 去除重复字母
    • [3171] 找到按位或最接近 K 的子数组
    • [322] 零钱兑换
    • [41] 缺失的第一个正数
    • [44] 通配符匹配
    • [494] 目标和
    • [509] 斐波那契数
    • [518] 零钱兑换 II
    • [62] 不同路径
    • [676] 实现一个魔法字典
    • 70 爬楼梯
    • [718] 最长重复子数组
    • [78] 子集
    • [82] 删除排序链表中的重复元素 II
    • [871] 最低加油次数
    • [88] 合并两个有序数组
    • [887] 鸡蛋掉落
    • 958.二叉树的完全性检验
    • [98] 验证二叉搜索树
    • [983] 最低票价
    • leetcode practice
    • 约瑟夫问题
    • 移除重复节点
  • linked-list

    • 706. 设计哈希映射
    • 链表
  • stack

    • stack
  • tree

    • Tree Traversal
    • 二叉树的最近公共祖先
    • 二叉树
    • 题目
  • leetCode 刷题
  • 回溯
  • 排序算法

[148] 排序链表

  1. 归并排序(Merge Sort):归并排序是一种有效的排序算法,适用于链表。它的时间复杂度为 O(nlogn)O(n log n)O(nlogn),空间复杂度为 O(logn)O(log n)O(logn)(递归调用栈的空间复杂度)。

  2. 插入排序(Insertion Sort):插入排序也可以用来对链表排序,时间复杂度为 O(n2)O(n^2)O(n2),但实现起来相对简单。

归并排序

归并排序是一种分治算法,先将链表分成两半,对每半链表递归排序,然后合并两个已排序的链表。归并排序特别适合链表,因为链表可以在 O(1) 时间内进行合并操作。

details
// 定义链表节点类
class ListNode {
    constructor(val = 0, next = null) {
        this.val = val;
        this.next = next;
    }
}

function sortList(head) {
    if (!head || !head.next) {
        return head;
    }

    // 分割链表
    let mid = getMiddle(head);
    let left = head;
    let right = mid.next;
    mid.next = null;

    // 递归排序两半链表
    left = sortList(left);
    right = sortList(right);

    // 合并两个已排序链表
    return merge(left, right);
}

function getMiddle(head) {
    let slow = head;
    let fast = head;
    while (fast.next && fast.next.next) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
}

function merge(left, right) {
    let dummy = new ListNode(0);
    let current = dummy;

    while (left && right) {
        if (left.val < right.val) {
            current.next = left;
            left = left.next;
        } else {
            current.next = right;
            right = right.next;
        }
        current = current.next;
    }

    if (left) {
        current.next = left;
    } else {
        current.next = right;
    }

    return dummy.next;
}
  1. 分割链表:

    • 使用快慢指针找出链表的中间节点,将链表分成两半。
  2. 递归排序:

    • 递归地对链表的左半部分和右半部分进行排序。
  3. 合并链表:

    • 使用归并操作将两个已排序的链表合并成一个已排序的链表。

插入排序

插入排序相对简单,但在链表上的时间复杂度较高。实现步骤包括创建一个新的链表,将节点逐一插入到合适的位置。

details
var sortList = function (head) {
    if (!head || !head.next) return head;

    let dummy = new ListNode(-Infinity);

    let cur = head;
    while (cur !== null) {
        let prev = dummy;
        let next = dummy.next;
        while (next !== null && next.val < cur.val) {
            prev = next;
            next = next.next;
        }

        let temp = cur.next;

        // next 链接到 dummy 上
        prev.next = cur;
        cur.next = next;

        cur = temp;
    }
    return dummy.next;
};
Last Updated:
Contributors: rosendo
Prev
[1306] 跳跃游戏 III
Next
155.最小栈