Java数据结构中链表分割及链表排序使用快速排序、归并排序、集合排序、迭代、递归,刷题的重点总结

news2024/9/17 8:18:07

本篇主要介绍在单链表进行分割,单链表进行分隔并使用快速排序、归并排序、集合排序、迭代、递归等方法的总结,愿各位大佬喜欢~~

86. 分隔链表 - 力扣(LeetCode)

148. 排序链表 - 力扣(LeetCode)


目录

一、分隔链表

二、排序链表

2.1先介绍一个最容易最简单的方法

2.2普通归并排序(自顶向下)

2.3借鉴大佬的归并排序(自底向上也是最难的,空间复杂度o(1))

2.4面试官让你用快排实现,不会做也得会

2.5快排2:


一、分隔链表

86. 分隔链表 - 力扣(LeetCode)

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

在分隔链表时,先考虑如何去分隔链表,怎么保证节点的next不形成环。

方法一:也是笨方法,找到第一个>x的值将小的值都逐个进行头插,随后将next指向第一个>x的值

class Solution {
    public ListNode partition(ListNode head, int x) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode mark = new ListNode(0, head);
        ListNode cur1 = mark;
        while (cur1.next != null && cur1.next.val < x) {
            cur1 = cur1.next;
        }
        ListNode firstMaxOrNull = cur1.next;
        ListNode cur2 = cur1;
        while (cur2 != null && cur2.next != null) {
            if (cur2.next.val >= x) {
                cur2 = cur2.next; 
            } else {
                cur1.next = cur2.next;
                cur2.next = cur2.next.next;
                cur1 = cur1.next;
                cur1.next = null;
            }
        }
        cur1.next = firstMaxOrNull;
        return mark.next;
    }
}

方法二:创建俩个链表进行分别插入,最后合并俩个链表

public ListNode partition(ListNode head, int x) {
        ListNode minLink = new ListNode(0);//记录小值链表的头
        ListNode minP = minLink;//对小表操作用的指针

        ListNode maxLink = new ListNode(0);//记录大值链表的头
        ListNode maxP = maxLink;//同理

        while(head!=null){
            if(head.val < x){//找到小的值
                minP.next = head;//放入minLink中,操作指针后移一位
                minP = head;
            }else{
                maxP.next = head;//放入maxLink中,操作指针后移一位
                maxP = head;
            }
            head = head.next;
        }
        //遍历完成后记得后一段链表的最后节点指向null;
        maxP.next = null;
        //两段拼接
        minP.next = maxLink.next;

        return minLink.next;
    }

二、排序链表

148. 排序链表 - 力扣(LeetCode)

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

上一道题并没有让合并之后还要进行排序,本题不仅要分隔之后还要进行排序,此时可以想到很多种方法,比如堆排序,快速排序,归并排序等等。看似简单,却是很多大厂的面试题。

2.1先介绍一个最容易最简单的方法

都存到集合中,排序后再进行赋值,如果写出这样,面试可能要回家喽!!!

class Solution {
    //思路,先把链表存到数组,排序后重新更新链表
    public ListNode sortList(ListNode head) {
        ArrayList<Integer> list = new ArrayList();
        ListNode p = head;
        while(p != null){
            list.add(p.val);
            p = p.next;
        }
        Collections.sort(list);
        p = head;
        for(int i = 0;i<list.size();i++){
            p.val = list.get(i);
            p = p.next;
        }
        return head;
    }
}

2.2普通归并排序(自顶向下)

使用快慢指针进行找到中间节点,然后进行归并排序

public ListNode sortList(ListNode head){
   return mergeSort(head);
}

// 找到一个链表的中点
    public ListNode findMid(ListNode head) {
        if (head == null) return head;

        ListNode fast = head.next;  // 快指针 每次走2步
        ListNode slow = head;       // 慢指针 每次走1步
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

public ListNode mergeSort(ListNode head) {
        // 当head.next==null时 说明当前链表只有一个元素 无序再排序
        if (head == null || head.next == null) {
            return head;
        }
        // 找到中间节点
        ListNode mid = findMid(head);
        // 存储中间节点的下一个结点
        ListNode next = mid.next;
        // 从中间结点断开 分别对两边进行mergeSort
        mid.next = null;
        // 返回排序后的头节点
        ListNode left = mergeSort(head);
        ListNode right = mergeSort(next);

        // 返回合并之后的头节点
        return merge(left, right);
    }

    public ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode curr = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                curr.next = l1;
                l1 = l1.next;
            } else {
                curr.next = l2;
                l2 = l2.next;
            }
            curr = curr.next;
        }

        if (l1 != null) {
            curr.next = l1;
        }

        if (l2 != null) {
            curr.next = l2;
        }
        return dummy.next;
    }

2.3借鉴大佬的归并排序(自底向上也是最难的,空间复杂度o(1))

class Solution {
    public ListNode sortList(ListNode head) {
        ListNode dummy = new ListNode(-1, head);
        // 获取链表的长度
        int len = 0;
        ListNode curr = head;
        while (curr!=null) {
            len++;
            curr = curr.next;
        }

        // 循环遍历
        // 外层遍历step 内层处理每step个元素进行一次merge
        for (int step=1; step<len; step*=2) {
            ListNode tail = dummy;
            curr = dummy.next;
            while (curr!=null) {
                ListNode left = curr;
                ListNode right = cut(left, step);
                curr = cut(right, step);
                tail.next = merge(left, right);
                while (tail.next!=null) {
                    tail = tail.next;
                }
            }
        }
    return dummy.next;
    }

    // 将链表从from开始切掉前step个元素,返回后一个元素
    public ListNode cut(ListNode from, int step) {
        step--;
        while (from!=null && step>0) {
            from = from.next;
            step--;
        }
        if (from==null) {
            return null;
        } else {
            ListNode next = from.next;
            from.next = null;
            return next;
        }
    }

    // 将两个有序链表合并成一个,返回合并后的头节点
    public ListNode merge(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode();
        ListNode curr = dummy;
        while (l1!=null && l2!=null) {
            if (l1.val<l2.val) {
                curr.next = l1;
                l1 = l1.next;
            } else {
                curr.next = l2;
                l2 = l2.next;
            }
            curr = curr.next;
        }
        if (l1!=null) {
            curr.next = l1;
        }
        if (l2!=null) {
            curr.next = l2;
        }
        return dummy.next;
    }
}

2.4面试官让你用快排实现,不会做也得会

public ListNode sortList3(ListNode head) {
        return quickSortLinkedList(head)[0];
    }

    public ListNode[] quickSortLinkedList(ListNode head) {
        if(head == null || head.next == null) return new ListNode[]{head,head};
        //pivot为head,定义跟踪分割左右两个链表的头尾指针
        ListNode p = head.next,headSmall= new ListNode(),
                headBig = new ListNode(),tailSmall = headSmall, tailBig = headBig;

        //partition操作,以pivot为枢纽分割为两个链表
        while(p != null){
            if(p.val < head.val){
                tailSmall.next = p;
                tailSmall = tailSmall.next;
            }else{
                tailBig.next = p;
                tailBig = tailBig.next;
            }
            p = p.next;
        }

        //断开<pivot的排序链表、pivot、>=pivot的排序链表,链表变为三个部分
        head.next = null;
        tailSmall.next = null;
        tailBig.next = null;

        //递归partition
        ListNode[] left = quickSortLinkedList(headSmall.next);
        ListNode[] right = quickSortLinkedList(headBig.next);


        //如果有<pivot的排序链表、连接pivot
        if(left[1] != null) {
            left[1].next = head;
        }
        //连接pivot、>=pivot的排序链表
        head.next = right[0];

        //确定排序后的头节点和尾节点
        ListNode newHead,newTail;
        if(left[0] != null) newHead = left[0];
        else newHead = head;
        if(right[1] != null) newTail = right[1];
        else newTail = head;

        //返回当前层递归排序好的链表头节点和尾节点
        return new ListNode[]{newHead,newTail};
    }

2.5快排2:

用6个指针,分别指向小于部分的头h1和尾t1、等于部分的头h2和尾t2、大于部分的头h3和尾t3

class Solution {
    public ListNode sortList(ListNode head) {
        return quickSort(head);
    }

    public ListNode quickSort(ListNode head) {
        if (head==null || head.next==null) {
            return head;
        }
        ListNode h1 = new ListNode();
        ListNode h2 = new ListNode();
        ListNode h3 = new ListNode();
        ListNode t1 = h1;
        ListNode t2 = h2;
        ListNode t3 = h3;
        ListNode curr = head;
        int pivot = getMid(head).val;  // 用中间节点的原因是,如果每次用最左边的结点,对于纯递增和纯递减的case就退化为O(n)

        while (curr!=null) {
            ListNode next = curr.next;
            if (curr.val < pivot) {
                curr.next = null;
                t1.next = curr;
                t1 = t1.next;
            } else if (curr.val == pivot) {
                curr.next = null;
                t2.next = curr;
                t2 = t2.next;
            } else {
                curr.next = null;
                t3.next = curr;
                t3 = t3.next;
            }
            curr = next;
        }

        // < 的链表和 > 的链表分别快排
        h1 = quickSort(h1.next);
        h3 = quickSort(h3.next);

        // h1链表不一定有元素 h2链表一定有元素 先把h2、h3连起来
        h2 = h2.next;
        t2.next = h3;
        // 如果h1链表为空 直接返回h2即可
        // 否则找到h1链表的结尾,连上h2的头
        if (h1==null) {
            return h2;
        } else {
            t1 = h1;
            // 找到t1链表的结尾
            while (t1.next!=null) {
                t1 = t1.next;
            }
            t1.next = h2;
            return h1;
        }
    }

    public ListNode getMid(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while (fast!=null && fast.next!=null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

}

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

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

相关文章

CAS概述

目录一、CAS与原子类1.1 CAS1.2 乐观锁与悲观锁1.3 原子操作类二、 synchronized优化2.1 轻量级锁2.2 轻量级锁-无竞争2.3 轻量级锁-锁膨胀2.4 重量级锁-自旋2.5 偏向锁2.6 synchronized-其他优化一、CAS与原子类 1.1 CAS CAS&#xff08;一种不断尝试&#xff09;即Compare …

2023年正在使用的设计资源网站分享

这篇文章&#xff0c;也将整理出我今年一直都在使用的设计资源网站&#xff01;作为设计师一定是离不开优质的资源网站的&#xff0c;我自己的话会每天都花一两个小时的时间去浏览自己的收藏的这些资源网站。哪怕只是简单的浏览&#xff0c;也可以在无形中增加自己对设计的“设…

rocketmq延时消息自定义配置

概述 使用的是开源版本的rocketmq4.9.4 rocketmq也是支持延时消息的。 rocketmq一般是4个部分&#xff1a; nameserver&#xff1a;保存路由信息broker&#xff1a;保存消息生产者&#xff1a;生产消息消费者&#xff1a;消费消息 延时消息的处理是在其中的broker中。 但是…

华为认证含金量如何?

一本证书是否有用&#xff0c;还要看它是否被市场所认可。 我们说华为认证HCIP有用&#xff0c;很大一部分还取决于它极高的适用性和权威性。华为是国内最大的生产销售通信设备的民营通信科技公司。 自2013年起&#xff0c;国家对网络安全极度重视&#xff0c;相继把国外的网…

rk3568 开发板Ubuntu系统说明

Ubuntu MinimalUbuntu Minimal系统基于Ubuntu 64bit系统构建&#xff0c;目前发布有Ubuntu18.04这个版本。与Ubuntu Desktop 相比具有以下特性&#xff1a;没有桌面环境&#xff0c;占用资源少&#xff0c;在简化网络管理之后&#xff0c;只需40M内存&#xff1b;针对嵌入式平台…

DFN: Dynamic Filter Networks-动态卷积网络

一、论文信息 论文名称&#xff1a;Dynamic Filter Networks 作者团队&#xff1a;NIPS2016 二、动机与创新 卷积层是通过将上一层的特征映射与一组过滤器进行卷积计算输出特征映射&#xff0c;滤波器是卷积层的唯一参数&#xff0c;通常用反向传播算法在训练中学习&#xff…

一个批量扫描shiro漏洞的工具

Update 1.扫描的判断逻辑,通过返回的rememberMe个数进行判断 2.添加了bypass功能,可以发送随机的请求方法 学习 原理 <1.2.4 shiro550 <1.4.2 shiro721 https://cloud.tencent.com/developer/article/1944738 需要成功登录(目前还没有添加 >1.4.2 换加密方…

kubeadm的部署、Dashboard UI以及连接私有仓库

目录 一、kubeadm 部署 K8S 集群架构 1、环境准备 2、所有节点安装docker 3、所有节点安装kubeadm&#xff0c;kubelet和kubectl 3、部署K8S集群 二、dashboard 部署 1、 安装dashboard 2、使用火狐或者360浏览器访问 三 、安装Harbor私有仓库 四、 内核参数优化方案 …

《FPGA学习》->呼吸灯

&#x1f34e;与其担心未来&#xff0c;不如现在好好努力。在这条路上&#xff0c;只有奋斗才能给你安全感。你若努力&#xff0c;全世界都会为你让路。呼吸灯&#xff0c;简而言之就像人类呼吸一样&#xff0c;有节奏的让LED灯从&#xff1a;灭->微微亮->微亮->亮-&g…

python HZK16字库使用

注&#xff1a; 从个人博客园移植而来 环境&#xff1a; windows7, python2.7 简介 偶然在网上看到热心网友使用python讲微信头像进行了组字&#xff0c;感觉很有意思&#xff0c;就做下研究。 感谢&#xff0c;原文参考: Python玩微信头像组字 需求的相关工具&#xff1a; …

spring cloud gateway 实现redis动态路由及自动项目路由上报

前言 spring cloud gateway默认为内存存储策略&#xff0c;通过配置文件加载的方式生成路由定义信息 可以看到&#xff0c;RouteDefinitionRepository继承了两个父接口&#xff0c;分别为RouteDefinitionLocator和RouteDefinitionWriter&#xff0c;RouteDefinitionLocator定…

Java并发知识点

文章目录1. start()和run()方法的区别&#xff1f;2. volatile关键字的作用&#xff1f;使用volatile能够保证&#xff1a;防止指令重排3. sleep方法和wait方法有什么区别&#xff1f;sleep()方法4. 如何停止一个正在运行的线程&#xff1f;方法一&#xff1a;方法二&#xff1…

MindFusion Diagramming for Java, 最新版 Crack

Diagramming for Java, V4.6.1 A unique Java Swing library for any type of flowchart.您需要的每一个图表功能 图表、方案、图形、网络、算法、树、图表 - 所有这些都是使用 MindFusion Diagramming for Java 工具快速轻松地构建的。结果令人着迷。 Java Dagram 库&#xff…

论文阅读 | Real-Time Intermediate Flow Estimation for Video Frame Interpolation

前言&#xff1a;ECCV2022 快速插帧方法 Real-Time Intermediate Flow Estimation for Video Frame Interpolation 引言 进行视频插帧目前比较常见的方法是基于光流法&#xff0c;分为两个步骤&#xff1a;1.通过光流对齐输入帧&#xff0c;融合对齐的帧 光流并不能直接同于…

CS224W课程学习笔记(三):DeepWalk算法原理与说明

引言 什么是图嵌入&#xff1f; 图嵌入&#xff08;Graph Embedding&#xff0c;也叫Network Embedding&#xff09; 是一种将图数据&#xff08;通常为高维稠密的矩阵&#xff09;映射为低微稠密向量的过程&#xff0c;能够很好地解决图数据难以高效输入机器学习算法的问题。…

arxiv2017 | 用于分子神经网络建模的数据增强 SMILES Enumeration

论文标题&#xff1a;SMILES Enumeration as Data Augmentation for Neural Network Modeling of Molecules论文地址&#xff1a;https://arxiv.org/abs/1703.07076代码地址&#xff1a;https://github.com/Ebjerrum/SMILES-enumeration一、摘要摘要中明显提出&#xff1a;先指…

TCP/IP网络编程——多播与广播

完整版文章请参考&#xff1a; TCP/IP网络编程完整版文章 文章目录第 14 章 多播与广播14.1 多播14.1.1 多播的数据传输方式以及流量方面的优点14.1.2 路由&#xff08;Routing&#xff09;和 TTL&#xff08;Time to Live,生存时间&#xff09;&#xff0c;以及加入组的办法14…

STM32开发(11)----CubeMX配置独立看门狗(IWDG)

CubeMX配置独立看门狗&#xff08;IWDG&#xff09;前言一、独立看门狗的介绍二、实验过程1.STM32CubeMX配置独立看门狗2.代码实现3.硬件连接4.实验结果总结前言 本章介绍使用STM32CubeMX对独立看门狗定时器进行配置的方法。门狗本质上是一个定时器&#xff0c;提供了更高的安…

华为云计算之容灾技术

容灾是物理上的容错技术&#xff0c;不是逻辑上的容错同步远程复制&#xff1a;主备距离≤200km&#xff0c;只有在主备设备上都写成功&#xff0c;才会告诉主机写成功&#xff0c;不会丢失数据异步远程复制&#xff1a;主备距离&#xff1e;200km&#xff0c;只要主设备上写成…

掌握MySQL分库分表(二)Mysql数据库垂直分库分表、水平分库分表

文章目录垂直分表拆分方法举例垂直分库水平分表水平分库小结垂直角度&#xff08;表结构不一样&#xff09;水平角度&#xff08;表结构一样&#xff09;垂直分表 需求&#xff1a;商品表字段太多&#xff0c;每个字段访问频次不⼀样&#xff0c;浪费了IO资源&#xff0c;需要…