【leetcode热题】排序链表

给你链表的头结点 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 = []
输出:[]

解法一

归并排序需要一个辅助方法,也就是对两个有序链表进行合并,在 21 题 已经讨论过。

至于归并排序的思想,这里就不多讲了,本科的时候用 Scratch 做过一个演示视频,感兴趣的可以参考 这里,哈哈。

那就直接放代码了。因为归并排序是一半一半的进行,所以需要找到中点。最常用的方法就是快慢指针去找中点了。

ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
}

上边的代码我加了一个 dummy 指针,就是想当节点个数是偶数的时候,让 slow 刚好指向前边一半节点的最后一个节点,也就是下边的状态。

1    2    3    4
     ^         ^
    slow      fast

如果 slow 和 fast 都从 head 开始走,那么当 fast 结束的时候,slow 就会走到后边一半节点的开头了。

当然除了上边的方法,在 这里 看到,还可以加一个 pre 指针,让它一直指向 slow 的前一个即可。

// step 1. cut the list to two halves
ListNode prev = null, slow = head, fast = head;

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

他们的目的都是一样的,就是为了方便的把两个链表平均分开。

public ListNode sortList(ListNode head) {
    return mergeSort(head);
}

private ListNode mergeSort(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode fast = dummy;
    ListNode slow = dummy;
    //快慢指针找中点
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }

    ListNode head2 = slow.next;
    slow.next = null;
    head = mergeSort(head);
    head2 = mergeSort(head2);
    return merge(head, head2);

}

private ListNode merge(ListNode head1, ListNode head2) {
    ListNode dummy = new ListNode(0);
    ListNode tail = dummy;
    while (head1 != null && head2 != null) {
        if (head1.val < head2.val) {
            tail.next = head1;
            tail = tail.next;
            head1 = head1.next;
        } else {
            tail.next = head2;
            tail = tail.next;
            head2 = head2.next;
        }

    }
    if (head1 != null) {
        tail.next = head1;
    }

    if (head2 != null) {
        tail.next = head2;
    }

    return dummy.next;

}

当然严格的说,上边的解法空间复杂度并不是 O(1),因为递归过程中压栈是需要消耗空间的,每次取一半,所以空间复杂度是 O(log(n))

递归可以去改写成迭代的形式,也就是自底向上的走,就可以省去压栈的空间,空间复杂度从而达到 O(1),详细的可以参考 这里-with-o(1)-space-complextity-and-o(nlgn)-time-complextity) 。

相关推荐

  1. LeetCode100】【排序

    2024-03-11 17:32:02       134 阅读
  2. LeetCode 100 | (下)

    2024-03-11 17:32:02       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-11 17:32:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-11 17:32:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-11 17:32:02       87 阅读
  4. Python语言-面向对象

    2024-03-11 17:32:02       96 阅读

热门阅读

  1. 阿尔巴尼亚借助ChatGPT加快欧盟入会进程

    2024-03-11 17:32:02       47 阅读
  2. 3.最长连续序列

    2024-03-11 17:32:02       33 阅读
  3. _note_01

    2024-03-11 17:32:02       37 阅读
  4. TypeScript 5.4 正式发布

    2024-03-11 17:32:02       37 阅读
  5. Spring MVC面试系列-01

    2024-03-11 17:32:02       36 阅读
  6. numpy和pytorch的tensor哪个效率更高?

    2024-03-11 17:32:02       46 阅读
  7. pycharm进入函数定义快捷键

    2024-03-11 17:32:02       39 阅读
  8. mysql的视图的基本概念

    2024-03-11 17:32:02       41 阅读
  9. ChatGPT Sora视频生成提示词/指令/prompt技巧汇总篇

    2024-03-11 17:32:02       113 阅读
  10. CCC联盟数字车钥匙Release 3

    2024-03-11 17:32:02       41 阅读
  11. 力扣第 388 场周赛(A~B)

    2024-03-11 17:32:02       38 阅读
  12. vue选项式API和组合式API区别-备忘

    2024-03-11 17:32:02       42 阅读
  13. Node.js概述与安装和运行

    2024-03-11 17:32:02       46 阅读
  14. 程序员如何选择职业赛道

    2024-03-11 17:32:02       47 阅读