LeetCode热题(JS版) - 148. 排序链表

94 阅读1分钟

题目

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 1:

image.png

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2: image.png

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

提示:

链表中节点的数目在范围 [0, 5 * 104] 内
-105 <= Node.val <= 105

进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

思路

解题思路 这道题可以使用归并排序来解决。归并排序基本思路是:将一个数组分成两个数组,分别排序后再合并,最终得到有序数组。

对于链表,我们可以使用快慢指针法,将链表分成两个大致相等的部分,然后对这两部分分别进行排序,最后合并这两部分。具体实现可以参考下面的代码。

代码实现

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

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

    var slow = head;
    var fast = head;

    while (fast && fast.next && fast.next.next) {
        slow = slow.next;
        fast = fast.next.next;
    }

    var middle = slow.next;
    slow.next = null;// 切断链表

    var left = sortList(head);
    var right = sortList(middle);

    return merge(left, right);
};

function merge (left, right) {
    var dummy = new ListNode(0);
    var cur = dummy;

    while (left && right) {
        if (left.val < right.val) {
            cur.next = left;
            left = left.next;
        } else {
            cur.next = right;
            right = right.next;
        }
        cur = cur.next;// 后移
    }

    if (left) cur.next = left;
    if (right) cur.next = right;

    return dummy.next;
}
  • 时间复杂度:O(nlogn)。
  • 归并排序的空间复杂度是O(n),其中n为链表的长度。主要是因为在合并的过程中需要额外的空间来存储合并后的链表。在代码实现中,我们使用了一个dummy节点来简化合并操作,因此空间复杂度为O(1)。

image.png