LeetCode 👉 HOT 100 👉 排序链表 - 中等题

670 阅读1分钟

「这是我参与2022首次更文挑战的第26天,活动详情查看: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 = []

输出:[]

思路

最常见的思路如下:

  • 将链表的每个节点放入数组 stack
  • 然后使用对数组的每个元素,按照对应的 val 排序
  • 遍历数组,将 stack[i].next = stack[i + 1] || 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}
     */
    var sortList = function(head) {
        if(!head) return head;

        // 链表节点放入数组中
        const stack = [];
        while (head) {
            stack.push(head);
            head = head.next;
        }

        // 排序
        stack.sort((a, b) => a.val - b.val);

        // 重新组合链表
        for(let i = 0; i < stack.length; i++) {
            stack[i].next = stack[i + 1] || null;
        }

        // 返回头节点
        return stack[0]
    };

上述解法由于调用了 sort Api,在不同平台的时间复杂度,包括使用的算法都不同,稳定性较低

思考: 对于链表的排序,如果想要将时间复杂度降低,使用 归并排序 是比较好的方法

归并 的两个主要步骤:

  • 1、,利用二分法,每次以链表的中间节点为分割点,将链表分为两部分,分别进行排序;递归执行,直到链表的长度小于等于1

  • 2、,将两个有序链表进行合并(传送门 ☞),返回头节点给上一步,层层向上,最后即可得出问题的答案


    /**
     * @param {ListNode} head
     * @return {ListNode}
     */
    var sortList = function(head) {
        if(!head || !head.next) return head;

        // 快慢指针
        let slow = head, fast = head;

        // 保存slow节点的前一个节点
        let prevSlow = null; 

        // 快指针每次走两步,慢指针走一步
        while(fast && fast.next) {
            prevSlow = slow;
            slow = slow.next;
            fast = fast.next.next;
        }

        // 解除 slow 节点的前序节点的指向
        prevSlow.next = null;

        // 递归执行排序
        const l1 = sortList(head);
        const l2 = sortList(slow);

        // 返回 合并后的链表
        return merge(l1, l2);
    };

    function merge(l1, l2) {
        if(!l1) return l2;
        if(!l2) return l1;

        const head = h = new ListNode(0);

        while(l1 && l2) {
            if(l1.val > l2.val) {
                h.next = l2;
                l2 = l2.next;
            } else {
                h.next = l1;
                l1 = l1.next;
            }

            h = h.next;
        }

        if(l1) h.next = l1;
        if(l2) h.next = l2;

        // 返回头节点
        return head.next;
    }

小结

归并排序的时间复杂度可以降低为 O(nLogn),记住先 ,将数据拆分入栈,最后将最小单元的数据重新组合,称为 ,就能牢记住该算法的主要思想。

LeetCode 👉 HOT 100 👉 排序链表 - 中等题

合集:LeetCode 👉 HOT 100,有空就会更新,大家多多支持,点个赞👍

如果大家有好的解法,或者发现本文理解不对的地方,欢迎留言评论 😄