【LeetCode-中等题】148. 排序链表

news2024/11/17 19:32:31

文章目录

    • 题目
    • 方法一:集合排序(核心是内部的排序)
    • 方法二: 优先队列(核心也是内部的排序)
    • 方法三:归并排序(带递归) 从上往下
    • 方法四:归并排序(省去递归,用迭代) 从下往上

题目

在这里插入图片描述

方法一:集合排序(核心是内部的排序)

把链表放到List集合,排好序,再依据List集合创建一个新有序链表返回就行了

//方法一 集合倒序  (存.val值在转换为ListNode)
    public ListNode sortList(ListNode head) {
        if(head == null) return head;
        List<Integer> list = new ArrayList<>();
        ListNode node = head;
        while(node != null){
            list.add(node.val);
            node = node.next;
        }
        Collections.sort(list);//升序排列
        ListNode min = new ListNode(list.get(0));//直接找出小值记录头结点
        node = min;
        for(int i = 1; i<list.size(); i++){
            ListNode h = new ListNode(list.get(i));
            node.next = h;
            node = node.next;
        }
        return min;
    }


// 方法一 集合倒序(存ListNode值直接调用Comparator接口进行值排序)
    //     public ListNode sortList(ListNode head) {
    //     if(head == null){
    //         return null;
    //     }
    //     List<ListNode> list  = new ArrayList<>();
    //     while(head !=null){
    //         list.add(head);
    //         head = head.next;
    //     }
    //     list.sort(new Comparator<ListNode>(){
    //         @Override
    //         public int compare(ListNode o1, ListNode o2) {
    //             return o1.val - o2.val;
    //         }
    //     });
    //     for(int i = 0 ; i < list.size() - 1;i++){
    //         list.get(i).next = list.get(i + 1);
    //     }
    //     list.get(list.size() - 1).next = null;
    //     return list.get(0);

方法二: 优先队列(核心也是内部的排序)

优先队列 往这个优先队列中插入元素时,会按照节点 val 属性的大小顺序进行排序,即小的节点排在前面,大的节点排在后面。依次谈栈再创建新链表
优先队列声明

PriorityQueue<ListNode> queue = new PriorityQueue<>((node1, node2) -> node1.val - node2.val);
  	((node1, node2) -> node1.val - node2.val)  升序排列
    ((node1, node2) -> node2.val - node1.val)  降序排列
 public ListNode sortList(ListNode head) {

        PriorityQueue<ListNode> queue = new PriorityQueue<>((node1, node2) -> node1.val - node2.val);

        ListNode cur = head;
        while (cur != null) {
            queue.offer(cur);
            cur = cur.next;
        }

        ListNode dummy = new ListNode(0);
        cur = dummy;
        while (!queue.isEmpty()) {
            cur.next = queue.poll();
            cur = cur.next;
        }
        cur.next = null;

        return dummy.next;
    }

方法三:归并排序(带递归) 从上往下

先找到中间点 按中间点切割链表 然后排序好切割好的两头的链表 再将两个排序好的链表合并起来 (递归终止条件是切割到只有一个节点,直接返回可以排序了)

  1. 先找到待排序链表的中间节点(快慢指针找)
  2. 再根据中间节点对两边的链表分别进行归并排序(递归)
  3. 将排序好的两部分链表进行合并( 双指针法 无需递归)

在这里插入图片描述

         public ListNode sortList(ListNode head) {
                    return mergeSort(head);
        }
          // 归并排序
          private ListNode mergeSort(ListNode head){
                if(head ==null || head.next==null) return head;// 如果没有结点/只有一个结点,无需排序,直接返回--也是递归的出口
                // 快慢指针找出中位点
                ListNode fast = head.next;//让fast比slow快1个位置,这样最后solw会停在链表中间点前一个位置
                // ListNode fast = head.next.next;//两种方式都可以  最终slow都会停在中间点前一个位置
                ListNode slow = head;
                 //记住这个判断条件,偶数结点会找靠左结点,奇数就是中间节点,能用到很多题上
                while(fast !=null && fast.next !=null){
                    slow =slow.next;
                    fast = fast.next.next;
                }
                // 对右半部分进行归并排序
                ListNode right = mergeSort(slow.next);
                
                // 对左半部分进行断链操作
                slow.next =null;

                // 对左半部分进行归并排序
                ListNode left = mergeSort(head);

                //合并两个有序链表
                return mergeList(left,right);
    
          } 


           // 合并链表  双指针法
          private ListNode mergeList(ListNode l,ListNode r){
              // 临时头节点
              ListNode tmpHead=new ListNode(-1);

            ListNode tem = tmpHead;
            while( l!=null && r!=null ){  //只循环走到任何一方为null时  后面就不需要再比较了  直接把多的哪一方拼接起来就行
                if(l.val < r.val){
                    tem.next =l;
                    l = l.next;
                }else{
                    tem.next =r;
                    r = r.next;
                }
                tem = tem.next;
            }
            if(l==null) tem.next = r;//只循环走到任何一方为null时  后面就不需要再比较了  直接不为null的哪一方拼接起来就行
            else tem.next =l;
            return tmpHead.next;
          }

方法四:归并排序(省去递归,用迭代) 从下往上

核心就行直接定义排序的最小单位 也就是一个节点的链表(大for循环从intv = 1(子俩表长度) 开始 在intv >= 大链表的长度停止),然后分别对链表长度为1 2 3 4 进行合并排序,然后拼接到一起,就是排序号的链表

在这里插入图片描述

 public ListNode sortList(ListNode head) {
            if(head == null) return head;
            int length = 0;//统计链表的长度
            ListNode node = head;
            while(node != null){
                length++;
                node = node.next;
            }
            ListNode preHead = new ListNode(0,head);//创建哑结点  preHead--->head

            for(int intv = 1; intv < length ;intv=intv*2){ //每次intv扩大两倍   直到intv 大于等于了链表的长度
               ListNode prev = preHead;//prev为拼接点(拼接合并好的链表)
               ListNode cur = preHead.next;
               while(cur != null){//开始拆分
                 ListNode head1 = cur;//intv为1 时的 第一段链表的头节点
                 for(int i = 1 ; i<intv&&cur.next !=null&& cur != null;i++){//找到intv为1 时的 第一段链表的末尾节点  方便找到第二段的头结点 
                        cur=cur.next;//此时循环结束   cur指向的是第一段链表的尾部 
                 }
                  ListNode head2 = cur.next;//intv为1 时的 第二段链表的头节点
                  cur.next = null;  //端链操作  将两部分链表断开
                  cur = head2;  //更新cur到第二段链表的首节点


                  for(int i = 1 ; i<intv && cur != null  && cur.next != null ; i++){
                             cur=cur.next;//此时 cur指向的是第二段链表的尾部
                  }

                  ListNode next = null;
                 if(cur != null){  //记录第二次进行 比较的  第一段链表的第一个节点
                     next = cur.next;
                     cur.next = null;//对第一次比较的第二个链表进行断链
                 }

                 ListNode merged = mergeList(head1,head2);//对第一次的两个链表进行合并排序
                 prev.next = merged;//将合并好的链表 拼接到prev后面
                while(prev.next != null){
                    prev = prev.next; //把prev移动到拼接好的链表的尾部,方便下次再拼接合并排序好的链表
                }
                cur = next;//将cur更新到下一批次合并排序的第一个俩表的头结点

               }
            }
            return preHead.next;
    }

    //        // 合并两个有序链表  双指针法
          private ListNode mergeList(ListNode l,ListNode r){
               // 临时头节点
            ListNode tmpHead= new ListNode(-1);
            ListNode tem = tmpHead;
            while( l!=null && r!=null ){  //只循环走到任何一方为null时  后面就不需要再比较了  直接把多的哪一方拼接起来就行
                if(l.val < r.val){
                    tem.next =l;
                    l = l.next;
                }else{
                    tem.next =r;
                    r = r.next;
                }
                tem = tem.next;
            }
            if(l==null) tem.next = r;//只循环走到任何一方为null时  后面就不需要再比较了  直接不为null的哪一方拼接起来就行
            else tem.next =l;
            return tmpHead.next;
          }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/946932.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【juc】读写锁ReentrantReadWriteLock

目录 一、说明二、读读不互斥2.1 代码示例2.2 截图示例 三、读写互斥3.1 代码示例3.2 截图示例 四、写写互斥4.1 代码示例4.2 截图示例 五、注意事项5.2.1 代码示例5.2.2 截图示例 一、说明 1.当读操作远远高于写操作时&#xff0c;使用读写锁让读读可以并发&#xff0c;来提高…

excel功能区(ribbonx)编程笔记--2 button控件与checkbox控件

我们上一章简单先了解了ribbonx的基本内容,以及使用举例实现自己修改ribbox的内容,本章紧接上一章,先讲解一下ribbonx的button控件。 在功能区的按钮中,可以使用内置图像或提供自已的图像,可以指定大按钮或者更小的形式,添加少量的代码甚至可以同时提供标签。此外,可以利…

Nginx到底是什么,他能干什么?

Ngnix是什么&#xff0c;它是用来做什么的呢&#xff1f; 一。Nginx简介 Nginx是enginex的简写&#xff0c;是一款很优秀的开源的高性能HTTP和反向代理服务器,由于它是用C语言写的&#xff0c;所以速度非常快&#xff0c;性能非常优秀&#xff0c;它主要功能就是反向代理&…

使用安全复制命令scp在Windows系统和Linux系统之间相互传输文件

现在已经有很多远程控制服务器的第三方软件平台&#xff0c;比如FinalShell&#xff0c;MobaXterm等&#xff0c;半可视化界面&#xff0c;使用起来非常方便和友好&#xff0c;两个系统之间传输文件直接拖就行&#xff0c;当然也可以使用命令方式在两个系统之间相互传递。 目录…

Java网络爬虫——jsoup快速上手,爬取京东数据。同时解决‘京东安全’防爬问题

Java网络爬虫——jsoup快速上手&#xff0c;爬取京东数据。同时解决‘京东安全’防爬问题 介绍 网络爬虫&#xff0c;就是在浏览器上&#xff0c;代替人类爬取数据&#xff0c;Java网络爬虫就是通过Java编写爬虫代码&#xff0c;代替人类从网络上爬取信息数据。程序员通过设定…

Spring Cloud Gateway的快速使用

环境前置搭建Nacos&#xff1a;点击跳转 Spring Cloud Gateway Docs 新建gateway网关模块 pom.xml导入依赖 <!-- 网关 --> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifact…

部署Spring Boot项目

上传jar包 之前在新建Spring Boot项目[1]使用mvn install的方式&#xff0c;已经构建出jar包。 通过scp或rz/sz&#xff0c;将该jar包上传到服务器 执行java -jar hello-0.0.1-SNAPSHOT.jar,发生如下报错&#xff1a; Exception in thread "main" java.lang.Unsuppo…

jsp+servlet+mysql阳光网吧管理系统

项目介绍&#xff1a; 本系统使用jspservletmysql开发的阳光网吧管理系统&#xff0c;纯手工敲打&#xff0c;系统管理员和用户角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;修改个人信息、修改密码&#xff1b;机房类型管理&#xff1b;机房管理&#xff1b;机位…

如何变更小程序会员卡的上级

在小程序中&#xff0c;手动变更会员的上级是一项常见的操作。无论是为了层级调整还是因个人原因&#xff0c;支持手动变更会员的上级可以有效地管理和优化团队的组织结构。下面就具体介绍如何手动变更会员的上级。 1. 找到指定的会员卡。在管理员后台->会员管理处&#xf…

vue项目静态文件资源下载

业务场景&#xff1a;页面有一个导入功能&#xff0c;需要一个模板文件供下载&#xff0c;文件放在本地。 对于 Vue 3 Vite 项目&#xff0c;使用 require 方法来导入模块是不被支持的。require 是 CommonJS 规范中用于模块导入的方法&#xff0c;在 Webpack 等构建工具中常用…

扩散模型实战(八):微调扩散模型

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#xf…

FPGA VR摄像机-拍摄和拼接立体 360 度视频

本文介绍的是 FPGA VR 相机的第二个版本&#xff0c;第一个版本是下面这样&#xff1a; 第一版地址&#xff1a; ❝ https://hackaday.io/project/26974-vr-camera-fpga-stereoscopic-3d-360-camera ❞ 本文主要介绍第二版本&#xff0c;第二版本的 VR 摄像机&#xff0c;能够以…

Python提取JSON文件中的指定数据并保存在CSV或Excel表格文件内

本文介绍基于Python语言&#xff0c;读取JSON格式的数据&#xff0c;提取其中的指定内容&#xff0c;并将提取到的数据保存到.csv格式或.xlsx格式的表格文件中的方法。 JSON格式的数据在数据信息交换过程中经常使用&#xff0c;但是相对而言并不直观&#xff1b;因此&#xff0…

Java学习笔记31——字符流

字符流 字符流为什么出现字符流编码表字符串中的编码解码问题字符流写数据的5中方式字符流读数据的两种方式字符流复制Java文件 字符流 为什么出现字符流 汉字的存储如果是GBK编码占用2个字节&#xff0c;如果是UTF-8占用三个字节 用字节流复制文本文件时&#xff0c;文本文…

华为---OSPF协议优先级、开销(cost)、定时器简介及示例配置

OSPF协议优先级、开销、定时器简介及示例配置 路由协议优先级&#xff1a;由于路由器上可能同时运行多种动态路由协议&#xff0c;就存在各个路由协议之间路由信息共享和选择的问题。系统为每一种路由协议设置了不同的默认优先级&#xff0c;当在不同协议中发现同一条路由时&am…

【USRP】调制解调系列3:2FSK、4FSK、8FSK,基于labview的实现

2FSK、4FSK、8FSK FSK&#xff08;Frequency-shift keying&#xff09;是信息传输中使用得较早的一种调制方式,它的主要优点是: 实现起来较容易,抗噪声与抗衰减的性能较好。在中低速数据传输中得到了广泛的应用。最常见的是用两个频率承载二进制1和0的双频FSK系统。 FSK 信号…

uni-app开发小程序,radio单选按钮,点击可以选中,再次点击可以取消

一、实现效果&#xff1a; 二、代码实现&#xff1a; 不适用官方的change方法&#xff0c;自己定义点击方法。 动态判断定义的值是否等于遍历的值进行回显&#xff0c;如果和上一次点击的值一样&#xff0c;就把定义的值改为null <template><view><radio-group&…

国产自主可控C++工业软件可视化图形架构源码

关于国产自主代替的问题是当前热点&#xff0c;尤其是工业软件领域。 “一个功能强大的全自主C跨平台图形可视化架构对开发自主可控工业基础软件至关重要&#xff01;” 作为全球领先的C工业基础图形可视化软件提供商&#xff0c;UCanCode软件有自己的思考&#xff0c;我们认…

Linux中的工具:yum,vim,gcc/g++,make/makefile,gdb

目录 1、yum 1.1 查看软件包&#xff1a; 1.2 安装软件包 1.3 卸载软件 2、vim 2.1 vim的三种模式 2.2 vim的基本操作 2.3. vim正常模式命令集 2.3.1 插入模式 2.3.2 移动光标 2.3.3 删除文字 2.3.4 复制 2.3.5 替换 2.3.6撤销上一次操作 2.3.7 更改 2.3.8 跳至…

WebGL模型矩阵

前言&#xff1a;依赖矩阵库 WebGL矩阵变换库_山楂树の的博客-CSDN博客 先平移&#xff0c;后旋转的模型变换&#xff1a; 1.将三角形沿着X轴平移一段距离。 2.在此基础上&#xff0c;旋转三角形。 先写下第1条&#xff08;平移操作&#xff09;中的坐标方程式。 等式1&am…