• 【刷题笔记10.5】LeetCode:排序链表


    LeetCode:排序链表

    一、题目描述

    给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    二、分析

    这题咱们默认要求:空间复杂度为O(1)。所以这把咱们用自底向上的方法实现归并排序,则可以达到O(1) 的空间复杂度

    具体算法如下:

    1、首先,判断如果所给的 head 为 null 则返回null
    2、求出所给链表head的长度length,然后将链表拆分成子链表进行合并。具体算法如下:

    • 2.1、用subLen表示每次需要排序的子链表的长度,初始值subLen为1.
    • 2.2、每次将链表拆分成若干个长度为subLen的子链表(最后一个子链表的长度可以小于subLen),按照每两个子链表一组进行合并(通过使用合并两个有序链表的做法),合并后即可得到若干个长度为 subLen2 的有序子链表(最后一个子链表的长度可以小于 subLen2)。合并两个子链表仍然使用合并两个有序链表的做法。
    • 2.3、将subLen的值加倍(通过位运算左移1位的方式),重复第2步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕。

    如何保证每次合并后得到的子链表都是有序的呢?可以通过数学归纳法证明。

    • 1、初始时subLen为1,每个长度为1的子链表都是有序的

    • 2、如果每个长度为subLen的子链表已经有序,那么合并两个长度为subLen的子链表后,得到长度为subLen * 2
      的子链表,一定也是有序的。

    • 3、当最后一个子链表的长度小于subLen时,该子链表也是有序的,合并两个链表之后得到的子链表一定也是有序的。

    三、上代码

    public class Deal11 {
        public ListNode sortList(ListNode head) {
            if (head == null) {
                return null;
            }
    
            //1、从头向后遍历链表,统计链表长度
            int length = 0;
            ListNode p = head;
            while(p != null) {
                length++;
                p=p.next;
            }
    
            //2、设定result用于记录最终返回结果,并对其进行最终的初始化
            ListNode result = new ListNode(-1);
            result.next = head;
    
            //3、将链表拆分成若干个长度为subLen的子链表,并按照没两个子链表一组进行合并
            for (int subLen = 1; subLen < length; subLen <<= 1) {//将subLen的值加倍(通过位运算左移1位的方式)
                ListNode pre = result;
                ListNode cur = result.next;   //用于记录拆分链表的位置
    
                while (cur != null) { //如果链表没有被拆完
                    //3.1 拆分出链表1,其长度为subLen
                    ListNode head_1 = cur;    //第一个链表的头,即cur
                    for (int i = 1; i < subLen && cur != null && cur.next != null; i++) {
                        cur = cur.next;
                    }
    
                    //3.2 拆分出链表2,其长度也为subLen
                    ListNode head_2 = cur.next; //第二个链表的头,即第一个链表尾部的下一个位置
                    cur.next = null; //断开第一个链表和第二个链表的连接
                    cur = head_2;    //第二个链表的头重新赋给cur
                    for (int i = 1; i < subLen && cur != null && cur.next != null; i++) {
                        cur = cur.next;
                    }
    
                    //3.3 再次断开第二个链表的的连接
                    ListNode next = null;
                    if (cur != null) {
                        next = cur.next;  //用于记录拆分完两个链表后结束的后序位置
                        cur.next = null;
                    }
    
                    //3.4 合并两个有序链表head_1 和 head_2
                    ListNode merge = mergeTwo(head_1, head_2);
                    pre.next = merge;
                    while (pre.next != null) {
                        pre = pre.next;
                    }
                    cur = next;
                }
            }
            return result.next;
        }
    
        //合并两个有序链表
        public ListNode mergeTwo(ListNode head1, ListNode head2) {
            ListNode result = new ListNode(-1);
            ListNode p = result;
    
            ListNode p1 = head1;
            ListNode p2 = head2;
            while(p1 != null && p2 != null) {
                if (p1.val > p2.val) {
                    p.next = p2;
                    p2 = p2.next;
                } else {
                    p.next = p1;
                    p1 = p1.next;
                }
                p = p.next;
            }
            if (p1 == null) {
                p.next = p2;
            }
            if (p2 == null) {
                p.next = p1;
            }
            return result.next;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
  • 相关阅读:
    【Java篇】回顾二进制文件和字节流
    React-Router源码分析-History库
    喜报|百华鞋业成功入选2022 年临沂市内外贸产品“三同”企业名单
    里奥哈大使撰文 | 来一场云旅行吧,盘点里奥哈那些美轮美奂的酒庄~
    Java 基础 进程与线程
    Blender导出FBX模型到Unity
    qt qml
    【前端】HTTP相关知识总结
    虚拟存储器
    Chrome跨域访问网络请求Cookies丢失的解决办法
  • 原文地址:https://blog.csdn.net/weixin_43950588/article/details/133586884