leetcode 148. 排序链表 归并排序 自顶向下 和 自底向上两种解法

博客围绕LeetCode 148排序链表题目展开,介绍两种归并排序解法。自顶向下归并排序时间复杂度O(nlogn),空间复杂度O(logn);自底向上归并排序时间复杂度同样为O(nlogn),但空间复杂度仅O(1)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

leetcode 148. 排序链表

解法一:自顶向下归并排序

class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSort(head, null);
    }

    /**
    * 实现自顶向下归并排序,归并区间为左闭右开区间:[head, tail)
     */
    private ListNode mergeSort(ListNode head, ListNode tail) {
        // 终止条件:归并区间不含节点 或 只含有一个节点
        if (head == null) return null;
        if (head.next == tail) {
            head.next = null;
            return head;
        }

        // 寻找待归并区间中点,以划分左右子区间,进行递归归并
        ListNode slow = head, fast = head;
        while (fast != tail) {
            slow = slow.next;
            fast = fast.next;
            if (fast != tail) fast = fast.next;
        }

        ListNode mid = slow;
        ListNode newHead1 = mergeSort(head, mid);
        ListNode newHead2 = mergeSort(mid, tail);
        // 合并两个归并后的有序链表
        ListNode merged = merge(newHead1, newHead2);
        return merged;
    }

    /**
    * 合并两个有序链表
     */
    private ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(), p = dummyHead, p1 = l1, p2 = l2;
        while (p1 != null && p2 != null) {
            if (p1.val < p2.val) {
                p.next = p1;
                p = p.next;
                p1 = p1.next;
            } else {
                p.next = p2;
                p = p.next;
                p2 = p2.next;
            }
        }
        if (p1 != null) p.next = p1;
        if (p2 != null) p.next = p2;
        return dummyHead.next;
    }
}
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(logn)

解法二:自底向上归并排序

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null) return null;

        // 统计链表长度
        int length = 0;
        ListNode p = head;
        while (p != null) {
            length++;
            p = p.next;
        }

        ListNode dummyHead = new ListNode(0, head);
        // 自底向上归并排序,即两两归并的子链表长度序列为:1, 2, 4, ..., n (length/2 < n < length)
        for (int subLength = 1; subLength < length; subLength <<= 1) {
            ListNode prev = dummyHead, curr = dummyHead.next;
            
            // 对于一个链表长度,可能会存在多次归并
            while (curr != null) {
                // 待归并子链表一
                ListNode head1 = curr;
                for (int i = 1; i < subLength && curr != null && curr.next != null; i++) curr = curr.next;
                
                // 待归并子链表二
                ListNode head2 = curr.next;
                // 断链
                curr.next = null;
                curr = head2;
                for (int  i = 1; i < subLength && curr != null && curr.next != null; i++) curr = curr.next;

                // 断链
                ListNode next = null;
                if (curr != null) {
                    next = curr.next;
                    curr.next = null;
                }

                // 归并两个子链表
                ListNode merged = merge(head1, head2);
                prev.next = merged;
                while (prev.next != null) prev = prev.next;
                curr = next;
            }
        }
        return dummyHead.next;
    }

    /**
    * 合并两个有序链表
     */
    private ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode(), p = dummyHead, p1 = l1, p2 = l2;
        while (p1 != null && p2 != null) {
            if (p1.val < p2.val) {
                p.next = p1;
                p = p.next;
                p1 = p1.next;
            } else {
                p.next = p2;
                p = p.next;
                p2 = p2.next;
            }
        }
        if (p1 != null) p.next = p1;
        if (p2 != null) p.next = p2;
        return dummyHead.next;
    }
}
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值