LeetCode 148:排序链表 【归并】

本文介绍了一种在O(nlogn)时间复杂度和常数级空间复杂度下对链表进行排序的方法,通过使用归并排序的递归和非递归版本,实现了链表的有效排序,并提供了详细的代码实现。

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

148. 排序链表

难度中等512

O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

思路

使用归并排序
递归版本 则需要 O(n)空间
非递归版本 则需要O(1) 空间

代码 非递归版本

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        int len = getListLen(head);
        int itrv = 1;
        while(itrv < len) {
            ListNode pre = dummy;
            ListNode h = dummy.next;
            // 找到合并链表的h1和h2头节点
            while(h!=null) {
                int i = itrv;
                ListNode h1 = h;
                for(; h != null && i > 0; i--) {
                    h = h.next;
                }
                // i>0说明没有链表2直接返回
                if(i > 0) break;
                ListNode h2 = h;
                i = itrv;
                for(; h != null && i > 0; i--) {
                    h = h.next;
                }
                // 求出两个链表的长度
                int c1 = itrv;
                int c2 = itrv - i;
                
                //合并
                while(c1 > 0 && c2 > 0) {
                    if(h1.val < h2.val) {
                        pre.next = h1;
                        h1 = h1.next;
                        c1--;
                    }else {
                        pre.next = h2;
                        h2 = h2.next;
                        c2--;
                    }
                    pre = pre.next;
                }
                pre.next = c1 > 0 ? h1 : h2;
                while(c1 > 0 || c2 > 0) {
                    pre = pre.next;
                    c1--;
                    c2--;
                }
                pre.next = h;
            }
            itrv*=2;
        }
        return dummy.next;
    }

    private int getListLen(ListNode head) {
        ListNode cur = head;
        int len = 0;
        while(cur != null) {
            len++;
            cur = cur.next;
        }
        return len;
    }
}

参考:LeetCode java 非递归版 dqf18620

代码 递归版本

class Solution {
    public ListNode sortList(ListNode head) {
        // 采用 归并排序 由于 归并排序过程中 使用的 空间
        // 先判断链表空不空
        if(head == null || head.next == null) return head;
        // 然后找到 分界点 使用双指针 即快慢指针寻找
        // 快慢指针 快指针 先指向 head.next 慢指针指向 head 快指针每次比慢指针多走两步 知道末位
        // 慢指针指的就是 后半部分的前一个节点  1->2->3->4  slow = 2
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast!=null && fast.next!=null){
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode temp = slow.next;
        // 断开两部分
        slow.next = null;
        // 进行分别排序
        ListNode left = sortList(head);
        ListNode right = sortList(temp);
        // 最后进行处理比如
        ListNode h = new ListNode(0);  // 一个辅助节点 装头
        ListNode res = h;
        while (left!=null && right!=null){
            if(left.val < right.val){
                h.next = left;
                left = left.next;
            }else {
                h.next = right;
                right = right.next;
            }
            h = h.next;
        }
        h.next = left !=null? left:right;
        return res.next;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值