LeetCode-148-排序链表

题目

在这里插入图片描述

思路

  1. 一个平淡无奇的解法:遍历链表并且将其存储在arraylist里,然后给arraylist排序,最后创建一个新链表返回…
  2. 要求 O(n log n) 时间复杂度和常数级空间复杂度。
  3. 时间复杂度是O(nlogn) 的排序算法包括归并排序、堆排序和快速排序,最适合链表的排序算法是归并排序。
  4. 如果自顶向下,则要考虑递归实现,此时因为递归会调用栈空间,故自顶向下归并排序的空间复杂度为O(logn)
  5. 如果要达到 O(1)的空间复杂度,则需要使用自底向上的实现方式

题解思路

自顶向下递归法

  1. 找到链表的中点,以中点为分界,将链表拆分成两个子链表。(快慢指针)
  2. 对两个子链表分别排序。
  3. 将两个排序后的子链表合并,得到完整的排序后的链表。
  4. 递归的终止条件是链表的节点个数小于或等于1,即当链表为空或者链表只包含1个节点时,不需要对链表进行拆分和排序。

自底向上归并排序

  1. 首先求得链表的长度length,然后将链表拆分成子链表进行合并。
  2. 用subLength 表示每次需要排序的子链表的长度,初始时subLength=1。
  3. 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于subLength),
  4. 按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于subLength×2)
  5. 将subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕。

代码(自顶向下递归)

    public ListNode sortList(ListNode head) {
        return sortList(head,null);
    }
    public ListNode sortList(ListNode head,ListNode tail){
        //如果没有节点了 就返回
        if(head == null) return head;
        if(head.next == tail){ //即只有一个节点的情况
            head.next=null;
            return head;
        }
        //有两个或两个以上节点 找到中点 快慢指针
        ListNode slow = head;
        ListNode fast = head;
        while (fast!=tail){
            slow = slow.next;
            fast = fast.next;
            if(fast!=tail) fast = fast.next;
        }
        //中点为slow这里
        ListNode mid = slow;
        //两端分别排序
        ListNode list1 = sortList(head,mid);
        ListNode list2 = sortList(mid,tail);
        //合并
        ListNode sorted = merge(list1,list2);
        return sorted;
    }
    合并有序链表
    public ListNode merge(ListNode head1,ListNode head2){
        //哑节点
        ListNode dummy = new ListNode();
        ListNode temp = dummy;
        ListNode temp1 = head1;
        ListNode temp2 = head2;
        while (temp1!=null && temp2!=null){
            if (temp1.val <= temp2.val) {
                temp.next = temp1;
                temp1 = temp1.next;
            } else {
                temp.next = temp2;
                temp2 = temp2.next;
            }
            temp = temp.next;
        }
        if (temp1 != null) {
            temp.next = temp1;
        } else if (temp2 != null) {
            temp.next = temp2;
        }
        return dummy.next;
    }

代码(自底向上归并排序)

    public ListNode sortList(ListNode head) {
        //特殊情况
        if(head == null) return head;
        int length=0;
        ListNode node = head;
        //求长度
        while (node != null){
            length++;
            node = node.next;
        }
        //哑节点
        ListNode dummy = new ListNode(0,head);
        //根据subLength开始切分链表
        for(int subLength = 1;subLength<length;subLength*=2){
            ListNode pre = dummy;
            ListNode cur = dummy.next;
            //一次选两个subLength长度的链表合并 合并到末尾算合并完一趟
            while (cur!=null){
                ListNode head1 = cur;
                for (int i=1;i<subLength&&cur.next!=null;i++) {
                    cur = cur.next;
                }
                ListNode head2 = cur.next;
                //第一段切下来
                cur.next=null;
                //开始从head2找
                cur = head2;
                for (int i=1;i<subLength&&cur!=null && cur.next!=null;i++) {
                    cur = cur.next;
                }
                //next指向合并好的链表的后一个未被合并的链表
                ListNode next = null;
                if(cur != null){
                    next = cur.next;
                    //切下head2
                    cur.next=null;
                }
                //合并head1 head2
                ListNode merged = merge(head1, head2);
                //pre指向合并好的节点的头
                pre.next = merged;

                while (pre.next != null) {
                    //pre要指向下一个头
                    pre = pre.next;
                }
                cur = next;
            }
        }
        return dummy.next;
    }

    合并有序链表
    public ListNode merge(ListNode head1,ListNode head2){
        //哑节点
        ListNode dummy = new ListNode();
        ListNode temp = dummy;
        ListNode temp1 = head1;
        ListNode temp2 = head2;
        while (temp1!=null && temp2!=null){
            if (temp1.val <= temp2.val) {
                temp.next = temp1;
                temp1 = temp1.next;
            } else {
                temp.next = temp2;
                temp2 = temp2.next;
            }
            temp = temp.next;
        }
        if (temp1 != null) {
            temp.next = temp1;
        } else if (temp2 != null) {
            temp.next = temp2;
        }
        return dummy.next;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值