【归并排序】【链表】LeetCode 148. 排序链表

题目链接

148. 排序链表

思想

  • 分割 cut 环节: 找到当前链表中点,并从中点将链表断开(以便在下次递归 cut 时,链表片段拥有正确边界)

    • 我们使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。

    • 找到中点 slow 后,执行 slow.next = None 将链表切断。

    • 递归分割时,输入当前链表左端点 head 和中心节点 slow 的下一个节点 mid(因为链表是从 slow 切断的)。

    • cut 递归终止条件: 当head.next == None时,说明只有一个节点了,直接返回此节点。

  • 合并 merge 环节: 将两个排序链表合并,转化为一个排序链表。

    • 双指针法合并,建立辅助ListNode dummy 作为头部。

    • 设置两指针 left, right 分别指向两链表头部,比较两指针处节点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表。

    • 返回辅助ListNode dummy 作为头部的下个节点 dummy.next。

    • 时间复杂度 O(l + r),l, r 分别代表两个链表长度。

  • 当题目输入的 head == None 时,直接返回None。

image

代码

class Solution {
    public ListNode sortList(ListNode head) {

        // end condition
        if (head == null || head.next == null) {
            return head;
        }

        // find the middle node
        ListNode slow = head;
        ListNode fast = head.next;

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

        // split the list into two parts
        slow.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(mid);

        // sort the two parts
        ListNode dummy = new ListNode(0);
        ListNode p = dummy;

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

        // merge the two parts
        if (left != null) {
            p.next = left;
        } else {
            p.next = right;
        }

        return dummy.next;
    }
}
posted @ 2022-12-30 21:24  Frodo1124  阅读(296)  评论(0编辑  收藏  举报