148. 排序链表(重要)

本文介绍了两种对链表进行排序的方法:归并排序和快速排序。归并排序通过分治策略将链表分成两半,然后分别排序再合并;而快速排序则采用中点分割,通过基准值划分链表,递归处理左右两部分。这两种算法都在O(nlogn)的时间复杂度内完成链表排序,并保持了常数级空间复杂度。

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

题目

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

进阶:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
例子

思路

归并

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSort(head);
    }
    public ListNode mergeSort(ListNode head){
        if (head == null || head.next == null){
            return head;
        }
        ListNode dummy = new ListNode();
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow =slow.next;
        }
        //找到中点
        ListNode mid = slow
        mid.next = null;
        //继续分割,左边分割
        ListNode left = mergeSort(dummy.next);
        //中点右边分割
        ListNode right = mergeSort(mid.next);
        //开始合并,第三个链表result用于合并
        ListNode result = new ListNode();
        ListNode p = result;
        while (left != null && right != null){
            //left小就放left.val到result
            if (left.val < right.val){
                p.next = left;
                left = left.next;
            } else {
                p.next = right;
                right = right.next;
            }
            p = p.next;
        }
        //防止长度不一致时还有剩余元素
        if (left == null){
            p.next = right;
        } else {
            p.next = left;
        }
        return result.next;
    }
}

快排

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        return quikSort(head);
    }
    public ListNode quikSort(ListNode head){
        //递归结束条件,只剩1个或者0个
        if (head == null || head.next == null){
            return head;
        }
        //找到中点位置,作为分割,用中点值作为基准分割链表为三部分
        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode mid = slow;
        int midVal = mid.val;
        //左边部分,即小于中点值
        ListNode left = new ListNode();
        //中间部分,即等于中点值
        ListNode middle = new ListNode();
        //右边部分,即大于中点值
        ListNode right = new ListNode();

        ListNode l = left;
        ListNode m = middle;
        ListNode r = right;
        //分链表
        while (head != null){
            if (head.val < midVal){
                l.next = head;
                head = head.next;
                l = l.next;
                l.next = null;
            } else if (head.val > midVal){
                r.next = head;
                head = head.next;
                r = r.next;
                r.next = null;
            } else {
                m.next = head;
                head = head.next;
                m = m.next;
                m.next = null;
            }
        }
        //分好后继续递归分
        l = quikSort(left.next);
        r = quikSort(right.next);
        //分好后中间部分之间连接右边
        m.next = r;
        //左边为空则直接返回中间头结点
        if (l == null){
            return middle.next;
        } else {
            //不为空则左边作为头节点,找到左边末尾直接连接中间节点
            ListNode newHead = l;
            while (l.next != null){
                l = l.next;
            }
            l.next = middle.next;
            return newHead;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值