数据结构-链表的简单操作代码实现2【Java版】

目录

写在前:

此篇讲解关于单链表的一些面试题目,续上节。

11.反转一个单链表

12.给定一个带有头结点的head的非空单链表,返回链表的中间结点,如果有两个中间结点,则返回第二个中间结点

13.输入一个链表,输出该链表中倒数第k个结点

14.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。

15.编写代码,以给定值x为基准将链表分为两部分,所有小于x的结点排在大于或等于x的结点之前

16.链表的回文结构

17.输入两个链表,找出他们的第一个公共结点

18.链表中是否有环

19.给定一个链表,返回链表开始入环的第一个结点,如果链表没有环,则返回null


11.反转一个单链表

给定一个链表:

进行反转后的链表:

这里我们采用的是“头插法”来解决问题。

首先需要进行判断

(1)当头结点不存在的时候返回null;【说明链表中没有元素】

(2)当头结点的next域为空时,返回头结点;【说明链表中只有一个结点】

当上面的两种情况都不是的时候

(1)定义一个cur结点指向head.next;

(2)将head.next的值置为null;

定义结点curNext指向cur.next;

进行“头插操作”:

第一步:

第二步:

第三步:

最后返回head。

    public ListNode reverseList(){
        if(head == null){
            return null;
        }
        //走到这里就说明链表里只有一个节点
        if(head.next == null){
            return head;
        }
        ListNode cur = head.next;
        head.next = null;
        while (cur != null){
            ListNode curNext = cur.next;
            //头插法插入cur(任何的插入都是先绑后面)
            cur.next = head;
            head = cur;
            cur = curNext;
        }
        return head;
    }

12.给定一个带有头结点的head的非空单链表,返回链表的中间结点,如果有两个中间结点,则返回第二个中间结点

将问题具象化:

如图,当我们有奇数个节点的时候,返回中间结点。

当我们有偶数个结点的时候返回第二个中间结点:

本题求解采用“快慢指针”

具体思路:

定义两个指针fast和slow,同时指向头结点的位置;每次让fast指针向前走两步,slow指针向前走一步。

当fast指针指向最后的位置的时候,此时fast.next域为空。这个时候slow指针指向的位置就是中间位置。

当链表中是偶数个结点的情况下同理:

以四个结点为例,同样的fast走两步,slow走一步;

当fast走到最后的时候此时fast为空。此时,slow所指向的位置就是中间结点中的第二个位置。

结合以上的分析,可以进行代码的编写:

定义两个结点指向头结点的位置。进入循环的条件为当fast指针域和fast.next域均不为空的时候,执行fast向后走两步,slow向后走一步的。

最后返回slow即为所求。

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

13.输入一个链表,输出该链表中倒数第k个结点

本题仍然使用“快慢指针”的方式来进行编写代码。

这里需要明确的是:在一个链表中倒数第k个结点需要走k-1步到链表的最后一个结点。

定义两个指针fast和slow;先让fast走k-1步,slow和fast再同时向前走;当fast.next为空的时候,此时slow所指的位置就是要求的倒数第k个结点。

编写代码:

首先进行合法性的判断当求得位置小于0或者当头结点为null的时候返回null;

定义两个指针fast和slow;

先让快指针向前走k-1步:这里需要判断的是当fast为null的时候就证明k的值大了,找不到对应的结点,此时也是返回null;

fast指针和slow指针同时向前走,当fast.next为空的时候,证明此时fast指向的链表的末尾,此时slow指向的位置就是需要找到的倒数第k个结点。

    public ListNode findKthToTail(int k){
        //当k不合法的时候
        if(k <= 0 || head == null){
            return null;
        }

        //当k合法时
        ListNode fast = head;
        ListNode slow = head;
        //1.fast走k-1步
        while (k - 1 != 0){
            fast = fast.next;
            if(fast == null){
                return null;
            }
            k--;
        }
        while (fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }

14.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。

    public static MySingleList.ListNode mergeTwoLists
            (MySingleList.ListNode head1,MySingleList.ListNode head2){
        MySingleList.ListNode newHead = new MySingleList.ListNode(0);
       MySingleList.ListNode tmp = newHead;
        while (head1 != null && head2 != null){
            if(head1.val < head2.val){
                tmp.next = head1;
                head1 = head1.next;
                tmp = tmp.next;
            }else {
                tmp.next = head2;
                head2 = head2.next;
                tmp = tmp.next;
            }

        }
        if(head1 != null){
            tmp.next = head1;
        }
        if(head2 != null){
            tmp.next = head2;
        }
        return newHead.next;
    }

15.编写代码,以给定值x为基准将链表分为两部分,所有小于x的结点排在大于或等于x的结点之前

现在我们有一个下图所示的链表:

根据所给题目的要求,我们最终实现的链表应该是如下的样子:

以上是一种情况:最后的末尾本身就是比28大的数据,所以这里不需要进行置空操作。

当末尾的元素需要变换的时候如图:(这里需要手动将最后一个元素的next域设置为null)

需要注意的点:

(1)是否需要进行对最后一个点进行处理

(2)怎么保证顺序不改变

定义一个cur,遍历链表。分成两段--如果小于28,就将数据放在第一段;如果大于28,就将数据放到第二段。

定义4个指针bs、be、as、ae.

定义cur遍历,当cur为空的时候表示链表遍历完成。

编写代码时需要注意:

当遍历完成后,需要考虑到:

有可能所给出的数据都大于给定的x值,或者都小于给定的x值。

如果第一段为空(bs == null)返回第二段as【这样同时解决了两段均为空的情况】

第一段不为空:be.next指向as;

最后将末尾置空【这里需要判空】

    public ListNode partition(int x){
        ListNode as = null;
        ListNode ae = null;
        ListNode bs = null;
        ListNode be = null;

        ListNode cur = head;
        while(cur != null){
            if(cur.val < x){
                if(bs == null){
                    bs = cur;
                    be = cur;
                }else{
                    be.next = cur;
                    be = be.next;

                }
            }else {
                if(as == null){
                    as = cur;
                    ae = cur;
                }else{
                    ae.next = cur;
                    ae = ae.next;
                }
            }
            cur = cur.next;
        }
        //有可能不会同时存在小于x 和大于等于x的数据
        if(bs == null){
            return as;
        }
        //第一段不为空
        be.next = as;
        //第2段不为空的问题
        if(as != null){
            ae.next = null;
        }
        return bs;
    }

16.链表的回文结构

链表的回文结构:

此题的解题思路是:首先找到链表的中间结点。

将后半部的链表进行反转。

定义两个指针,一个从头开走,一个从尾走。

走完后head在头部,slow走到了链表末尾。一个向前,一个向后

最后当两个指针如果相遇,则链表是回文结构的。

需要注意的是以上情况是链表中有奇数个结点的时候,

当存在偶数个结点的时候,需要在判断两个指针是否相等的时候进行进一步的进行判断。

    public boolean chkPalindrome(){
        if(head == null){
            return  false;
        }
        if(head.next == null){
            return true;
        }
        ListNode fast = head;
        ListNode slow = head;
        //1.找中间节点
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        //2.翻转
        ListNode cur = slow.next;//cur代表当前需要翻转的节点
        while(cur != null){
            ListNode curNext = cur.next;
            cur.next = slow;
            slow = cur;
            cur = curNext;
        }
        //3.一个从头往后,一个从后往前
        while (slow != head){
            if(head.val != slow.val){
                return false;
            }
            //偶数情况的判断
            if(head.next == slow){
                return true;
            }
            slow = slow.next;
            head = head.next;
        }
        return true;
    }

17.输入两个链表,找出他们的第一个公共结点

求两个链表的公共结点。

首先分别求出两个链表的长度。定义两个指针pl、ps分别指向两个链表的头结点headA和headB;

遍历完后将pl和ps指回两个链表的头部。

根据求得的len值,进行修改指针的指向:pl指向长的链表头结点;ps指向短的链表头结点;

让pl先走len步,然后二者同时向后走。

当相等的时候进行判空,为空返回null,不为空返回对应结点pl;

    public static MySingleList.ListNode getIntersectionNode
            (MySingleList.ListNode headA,MySingleList.ListNode headB){
        //1.分别求两个链表的长度
        int lenA = 0;
        int lenB = 0;
        MySingleList.ListNode pl = headA;
        MySingleList.ListNode ps = headB;

        while (pl != null){
            lenA++;
            pl = pl.next;
        }
        while(ps != null){
            lenB++;
            ps = ps.next;
        }
        //求完长度之后将pl和ps指回来
        pl = headA;
        ps = headB;
        int len = lenA - lenB;
        //根据len的值,修改指向
        if(len < 0){
            pl = headB;
            ps = headA;
            len = lenB - lenA;
        }
        //1.可以保证len一定是一个正数
        //2.pl指向的链表一定是最长的,ps指向的链表一定是最短的
        while (len != 0){
            pl = pl.next;
            len -- ;
        }
        while (pl != ps){
            pl = pl.next;
            ps = ps.next;
        }
        //pl == ps
        if(pl == ps && pl == null){
            return null;
        }
        return pl;
    }

18.链表中是否有环

判断环的问题其实本质上就是数学上的追击问题。

思路:快慢指针,慢指针一次走一步,快指针一次走两步。两个指针从链表起始位置开始走。如果链表有环则一定会在环中相遇,否则快指针率先到达链表的末尾。

拓展1:

为什么快指针每次走两步,慢指针每次走一步是可行的?

假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了。最差情况下两个指针之间的距离刚好是环的长度,此时两个指针每移动一次,之间的距离就缩小了一步,不会出现每次刚好套圈的情况。因此,在慢指针走到一圈之前,快指针一定是可以追的上慢指针的。

拓展2:

快指针一次走3步,走4步,...n步行么?

假设:快指针每次走三步,慢指针每次走一步,此时快指针一定是先进环的,慢指针后来才进环,假设慢指针进环的时候,快指针的位置:

此时按照上述方法来环绕移动,每次快指针走3步,慢指针走1步,是永远都不会相遇的,快指针刚好将慢指针套圈了,因此是不行的。

只有快指针走2步,慢指针走一步才可以,因为换的最小长度是1,即使套圈了两个也在相同的位置。

编写代码:

定义两个结点:fast和slow,均指向头结点。

当fast不等于null并且fast.next不等于null时进入循环,fast指针向后走两步,slow指针向后走一步,当fast和slow的指针指向同一位置的时候就说明链表存在环,返回true;否则返回11false。

    public boolean hasCycle(){
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                return true;
            }
        }
        return false;
    }

另外一种写法是在循环中判断fast和slow的指向的时候,break跳出循环。

这时在循环外面判断:如果是因为while循环跳出来的,就返回false;

如果是因为if条件跳出来的,返回true。

    public boolean hasCycle(){
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
               break;
            }
        }
        if(fast == null || fast.next == null){
            return false;
        }
        return true;
    }

19.给定一个链表,返回链表开始入环的第一个结点,如果链表没有环,则返回null

本题的思路:

涉及到一些数学的内容,下面进行分析

   public ListNode detectCycle(){
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                break;
            }
        }
        if(fast == null || fast.next == null){
            return null;
        }
        //有环,此时fast和slow就相遇了
        slow = head;
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是流程图,流程图怎么画?实名推荐这3个好用的在线流程图软件!

流程图是表达工作流程或者系统操作过程的有效工具&#xff0c;被广泛应用于各个行业和领域。他们以视觉的形式将复杂的流程简化&#xff0c;便于理解、交流和优化。不论是计划新项目、审计工作流程&#xff0c;还是改进现有操作&#xff0c;流程图都是一个不可或缺的工具。 什…

Mysql-表的结构操作

1.创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎 ; 说明&#xff1a; field 表示列名 datatype 表示列的类型 character set 字符集&#xff0c;如果没有指定字…

人工智能与多平台自动引流应用的结合

人工智能的技术在多平台自动引流方面的应用非常广泛&#xff0c;下面举例说明&#xff1a; 智能推荐算法&#xff1a;人工智能的推荐算法能够根据用户的兴趣和行为数据&#xff0c;自动向其推荐相关的内容和产品&#xff0c;从而引导用户访问和购买。这种多平台自动引流的方式可…

UITableView的style是UITableViewStyleGrouped

一般情况下&#xff0c;UITableViewStylePlain和UITableViewStyleGrouped是UITableView常用到的style&#xff0c; 之前都是用到的时候&#xff0c;遇到问题直接用度娘&#xff0c;差不多就够用了&#xff0c;今天在修复UI提出的间隙问题&#xff0c;来回改&#xff0c;总觉得…

Clickhouse 学习笔记(7)—— 查看执行计划

在 clickhouse 20.6 版本之前要查看 SQL 语句的执行计划需要设置日志级别为 trace 才能 可以看到&#xff0c;并且只能真正执行 sql&#xff0c;在执行日志里面查看 在20.6版本之后可以通过explain语句查看执行计划 基本语法 EXPLAIN [AST | SYNTAX | PLAN | PIPELINE] [se…

OpenAtom OpenHarmony三方库创建发布及安全隐私检测

OpenAtom OpenHarmony三方库&#xff08;以下简称“三方库”或“包”&#xff09;&#xff0c;是经过验证可在OpenHarmony系统上可重复使用的软件组件&#xff0c;可帮助开发者快速开发OpenHarmony应用。三方库根据其开发语言分为2种&#xff0c;一种是使用JavaScript和TypeScr…

phono3py快速安装教程

phono3py是类似于Phonopy的另一款基于第一性原理计算获得材料声学性质并可后处理的功能强大的软件&#xff0c;在以往推送内容中也有介绍基于phono3py 计算晶格热导率VASPphono3py:快速计算晶格热导率 和声子寿命理论到实践&#xff1a;VASPPhono3py计算Phonon Lifetime 以及…

速锐得HJ1239车载终端TBOX柴油商用车远程排放管理工况模型应用

其实排放模型&#xff0c;并不是生涩难懂的问题&#xff0c;首先我们准备好一台TBOX&#xff0c;比如无论是海康、华为、速锐得、博世、联电、LG、西门子都可以做到&#xff0c;在满足TBOX具备4G物联网2路CAN支持远程升级控车&#xff0c;支持国四国五国六车型&#xff0c;带定…

Python实现猎人猎物优化算法(HPO)优化XGBoost分类模型(XGBClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的…

前后端交互案例,图书管理系统

先引入前端代码运行看看是否有问题 图书管理系统 定义前后端交互接口 1.登录 URL : /user/login 参数 : userName?&password? 响应 : true/false 2.图书列表展示 : URL : /book/getBookList 参数 : 无 响应 : List<BookInfo> 后端代码如下: package com…

飞天使-django概念之urls

urls 容易搞混的概念&#xff0c;域名&#xff0c;主机名&#xff0c;路由 网站模块多主机应用 不同模块解析不同的服务器ip地址 网页模块多路径应用 urlpatterns [ path(‘admin/’, admin.site.urls), path(‘’, app01views.index), path(‘movie/’, app01views.movi…

完整版Java电子病历EMR编辑器系统源码

电子病历&#xff08;EMR&#xff09;是提供给医院机构内部使用&#xff0c;利用电子计算机保存、管理、传输和重现数字化的病人的医疗记录&#xff0c;在此基础上充分考虑患者信息的保密性&#xff0c;提高医疗质量和医治效率等服务功能的计算机信息系统。 一、电子病历编辑器…

成都爱尔周进院长解析高度近视可能引发哪些疾病

当代各类人群面对电脑、手机屏幕的时长显著增加&#xff0c;导致用眼过度、疲劳&#xff0c;视觉质量下降&#xff0c;近视人群越来越多。而当父母有一方为高度近视甚至可能将近视遗传给孩子。 目前&#xff0c;全球近视人数约25亿&#xff0c;中国近视人群人数多达6亿。据预测…

美国BGP服务器有哪些优势?

​  在当今数字化时代&#xff0c;网络连接的性能和可靠性对于企业和个人来说至关重要。而美国作为全球互联网的中心之一&#xff0c;其地区BGP服务器拥有许多优势。  网络性能和可靠性&#xff1a;美国BGP专线服务器采用BGP协议&#xff0c;一种高级动态路由协议&#xff…

幼师一旦开窍,工作真的没有这么难

真心希望所有新手幼教老师都能知道啊 只有输入关键词和要求&#xff0c;几秒就能生成一篇教案&#xff0c;从教学目标到教学内容都能给你安排的妥妥的。而且可以多次生成&#xff0c;每次生成都是不一样的内容。 什么教案、发言稿、总结、评语都能用的上啊&#xff0c;幼师姐…

计算机网络:IP 地址的编址

IP 地址的编址方式经历了三个历史阶段&#xff1a; 1. 分类的 IP 地址&#xff1b; 2. 子网的划分&#xff1b; 3. 构成超网。 1. 分类的 IP 地址 由两部分组成&#xff0c;网络号和主机号&#xff0c;其中不同类别具有不同的网络号长度&#xff0c;并且是固定的。 IP 地址 :: …

2024年武汉市中级工程师职称申报流程

很多人评审职称不知道职称申报需要走哪些步骤&#xff0c;不是很了解职称申报的一个过程&#xff0c;今天秋禾火告诉大家武汉职称申报流程是哪些&#xff0c;带你快速了解 首先是职称申报方式 职称评审目前是系统网上申报和线下送审纸质材料的双结合方式申报个人通过“湖北省…

系统韧性研究(4)| 系统韧性的技术分类

系统韧性技术是任何提高系统韧性的架构、设计或实现技术。这些技术&#xff08;例如缓解措施&#xff0c;如冗余、保障措施和网络安全对策&#xff09;或被动地抵御逆境或主动检测逆境&#xff0c;并对其做出反应&#xff0c;亦或者从它们造成的伤害中恢复过来。系统韧性技术是…

Makefile的简单语法学习

通配符 假如一个目标文件所依赖的依赖文件很多&#xff0c;那样岂不是我们要写很多规则&#xff0c;这显然是不合乎常理的&#xff0c;我们可以使用通配符&#xff0c;来解决这些问题。 我们对上节程序进行修改&#xff0c;代码如下&#xff1a; test : a.o b.ogcc -o test $…

腾讯云服务器多少钱一年?2023年腾讯云优惠云服务器推荐

作为一名程序员&#xff0c;技术的突飞猛进是从拥有第一台云服务器开始的。那时&#xff0c;我开始尝试使用Linux系统&#xff0c;并成功上线了自己的第一个小程序。自此之后&#xff0c;我和我的同事们都开始拥有自己的云服务器&#xff0c;用来搭建各种小项目或者好玩的东西。…