每日一题---OJ题: 环形链表 II

news2024/12/23 6:02:22

片头

嗨! 小伙伴们,大家好! 我们又见面啦,在上一篇中,我们学习了环形链表I, 今天我们继续来打boss,准备好了吗? Ready Go ! ! ! 

emmm,同样都是环形链表,有什么不一样的地方呢?

肯定有, 要不然也不会一个标记为"简单" ,一个标记为"中等"了,哈哈哈哈哈

让我们分析一下题目,哦~,原来是要返回链表开始入环的第一个结点呀! 上一个题目只是让我们简单的判断一下链表中是否有环,看来这次要求比上一次更高了,不怕不怕,一起来做一做~~~

举个例子:

在上图中,总共有4个结点,分别为 3, 2, 0, -4, 链表中有一个环,尾结点连接到第二个结点,返回第二个结点。

上图中,总共有2个结点, 分别为 1, 2, 链表中有一个环,尾结点连接到第一个结点,返回第一个结点。

上图中,只有1个结点,链表没有环,返回NULL

针对这道题,有两种思路,我们一起来看看吧!

思路一:  我们定义两个指针,分别为 fast 和 slow指针, slow指针每次走1步,fast指针每次走2步,利用 fast 和 slow 之间的数学逻辑关系,来解答此题。

当slow指针走到中间的时候,fast指针开始进环

链表头->入口点: L

当slow指针开始进环的时候,fast指针在环中可能已经走了n圈了

 此时,fast指针和slow指针都在环里面,slow指针进环以后开始追击。在上一章中,我们知道,当fast和slow之间的速度只相差1个单位的时候,fast指针一定能追上slow,最终两指针相遇。

链表头->入口点: L

入口点->相遇点: X

环的长度: C

追上相遇时: slow走的距离: L+X

追上相遇时: fast走的距离: L+ n*C + X  (假设fast追上slow时,转了n圈 (n>=1))

思考: slow有没有可能转了超过1圈? 没有! 因为slow都走了一圈了,那么fast走了2圈了,早追上了。

fast 追上slow时,fast走的距离是slow的2倍,我们可以列一个等式:

                      2*(L+X) = L + n*C + X

                            L+X = n*C 

                               L = n*C - X

哈哈哈,重头戏来咯! 我们可以得到一个结论: 一个指针从链表头开始走,一个指针从相遇点开始走,它们都以相同的速度(每次一步)进行移动,最终它们会在入口点相遇。

所以,基于这个结论,这道题的代码如下:

  typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
        ListNode* fast = head;      //初始时,定义一个fast指针指向头结点
        ListNode* slow = head;      //初始时,定义一个slow指针指向头结点
        while(fast && fast->next)   //当fast为空或者fast->next为空,则跳出循环
        {
            fast = fast->next->next;//fast每次走2步
            slow = slow->next;      //slow每次走1步
            if(fast == slow)        //如果fast和slow相遇
            {
                ListNode* meet = slow;//定义一个meet结点,用来找入口点
                while(meet != head)   //只有当两个指针再次相遇,循环才结束
                {
                    meet = meet->next;//meet每次走一步
                    head = head->next;//head每次走一步
                }
                return meet;          //当两个指针再次相遇时,即入环的第一个结点
            }
        }
        return NULL;            //如果fast为空或者fast->next为空,说明链表里面没有环
}

emmm,有的小伙伴会这样说: 哎呀,我想不起来这个推导过程以及结论,有没有其他的思路?

当然有! 且听我慢慢道来~

思路二:  我们定义两个指针,分别为 fast 和 slow指针, slow 指针每次走1步, fast 指针每次走2步, 当它们第一次相遇的时候,我们就把这个环断开,变成两个单链表,查找相交结点。

嗯,有点不太好理解,咱们画个图吧!

上图中,总共有8个结点,分别为 a1, a2, b1, b2, b3, c1, c2, c3 ,链表中有一个环,由 c3 结点指向 b1 结点, 题目要求我们把第一个相交结点(也就是 c1 结点)返回。

同理,我们先让fast指针每次走2步,slow指针每次走1步,它们最终会在 b2 结点相遇。

第一次:

第二次:

第三次:

第四次:

第五次:

第六次:

当快慢指针第一次相遇时,我们用meet结点来代表它们相遇的结点。用meet结点next指针(meet->next)指向headx结点,随后meet结点next指针指向NULL。

也就变成了这样:

变成了2个单链表, 分别是 a1->a2->c1->c2->c3->b1->b2b3->c1->c2->c3->b1->b2

现在我们需要求两个单链表第一次相交的结点,哈哈哈,求链表开始入环的第一个结点瞬间变成了求两个单链表的第一次相交的交点,好神奇~

注意: 小伙伴们如果不会求两个链表相交的起始结点,可以参考这篇文章相交链表(点击蓝色字体可以跳转相应的文章)

整体代码如下:

   typedef struct ListNode ListNode;
 struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB){
        ListNode* pA = headA;   //pA指针指向头结点(链表头)
        ListNode* pB = headB;   //pB指针指向头结点(链表头)

        int lenA = 0;           //统计链表A的长度
        while(pA->next != NULL) //查找链表A的尾结点
        {
            pA = pA->next;      //pA会一直遍历到尾结点      
            lenA++;             //每走过一个结点,链表A的长度自增一次        
        }
        lenA = lenA + 1;        //不要忘了尾结点

        int lenB = 0;           //统计链表B的长度
        while(pB->next != NULL) //查找链表B的尾结点
        {
            pB = pB->next;      //pB会一直遍历到尾结点      
            lenB++;             //每走过一个结点,链表A的长度自增一次        
        }
        lenB = lenB + 1;         //不要忘了尾结点

        if(pA != pB){            //如果尾结点不相同,说明链表A和链表B根本不会相交
            return NULL;         //返回NULL
        }

         //求链表A和链表B的长度差
        int gap =abs(lenA-lenB);       
        //假设链表A的长度比链表B短,那么将A链表定义为shortList
        ListNode* shortList = headA; 
      //假设链表B的长度比链表A长,那么将B链表定义为longList   
        ListNode* longList = headB;   
        if(lenA > lenB)
        {                               //如果链表A的长度大于链表B
            shortList = headB;          //将链表B定义为shortList
            longList = headA;           //将链表A定义为longList
        }
        while(gap--){                   //让长的链表先走长度差
            longList = longList->next;  
        }

        //现在长的链表和短的链表起始位置和尾结点的距离相同
        //让他们每一个结点依次比较,直到找到第一个相同的结点为止(也就是交点)
        while(shortList != longList)    
        {
            longList = longList->next;
            shortList = shortList->next;
        }
        return shortList;   //找到交点了,将这个结点返回
 }

struct ListNode *detectCycle(struct ListNode *head) {
       ListNode* fast = head;                //定义一个fast指针,指向链表头
       ListNode* slow = head;                //定义一个slow指针,指向链表头
       while(fast && fast->next)             //当fast为空或者fast->next为空时,退出循环
       {
            fast = fast->next->next;         //fast指针每次走2步 
            slow = slow->next;               //slow指针每次走1步
            if(fast == slow)                 //如果fast指针和slow指针第一次相遇
            {
         //定义一个变量meet,用来保存它们第一次相遇的结点
                ListNode* meet = slow;   
        //定义一个变量headx,将meet的next指针指向headx
                ListNode* headx = meet->next;
        //将meet结点的next指针置为NULL
                meet->next = NULL;        

                return getIntersectionNode(head,headx);//将找到的相交结点返回
            }
       }
       return NULL;  //如果fast为空,或者fast->next为空,说明链表没有成环,返回NULL
}

片尾

今天我们学习了一道OJ题---环形链表II ,这道题是在上一篇(环形链表)的基础上,难度稍微提高,不仅需要我们判断链表中是否存在环,如果链表中成环,我们还需要求出入环的第一个结点并返回,但是,这道题如果仔细想一想,还是可以做出来,希望看完这篇文章能对友友们有所帮助 !   !   !

点赞收藏加关注 !   !   !

谢谢大家 !  !  !

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

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

相关文章

2024年MathorCup数学建模A题移动通信网络中PCI规划问题解题文档与程序

2024年第十四届MathorCup高校数学建模挑战赛 A题 移动通信网络中PCI规划问题 原题再现: 物理小区识别码(PCI)规划是移动通信网络中下行链路层上,对各覆盖小区编号进行合理配置,以避免 PCI 冲突、PCI 混淆以及 PCI 模3 千扰等现象。PCI 规划…

基于SpringBoot+Vue的毕业生学历证明系统(源码+文档+部署+讲解)

一.系统概述 快速发展的社会中,人们的生活水平都在提高,生活节奏也在逐渐加快。为了节省时间和提高工作效率,越来越多的人选择利用互联网进行线上打理各种事务,然后线上管理系统也就相继涌现。与此同时,人们开始接受方…

git submodule---同步最新的内容

0 Preface/Foreword 1 同步最新submodule内容到repo中 项目的repo包含了一个子模块,在开发过程中,经常需要同步子模块最新的commit到repo中。该如何操作呢? 本地在克隆时候,已经同步把子模块中的内容克隆下来了,但是…

Rust跨平台编译

❝ 如果你感觉自己被困住了,焦虑并充满消极情绪,生命出现了停滞,那么治疗方法很简单:「做点什么」。 ❞ 大家好,我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder 前言 之前我们不是写了一篇R…

潍微科技-水务信息管理平台 ChangePwd SQL注入漏洞复现(CNVD-2024-14945)

0x01 产品简介 水务信息管理平台主要帮助水务企业实现水质状态监测、管网运行监控、水厂安全保障、用水实时监控以及排放有效监管,确保居民安全稳定用水、环境有效保护,全面提升水务管理效率。由山东潍微科技股份有限公司研发,近年来,公司全力拓展提升水务、水利信息化业务…

Java---搭建junit4.x单元测试环境,并进行测试

搭建junit4.x单元测试环境 1.选择Project Structure 2.选择Modules,选择要加入测试环境的模块,选择Dependencies,可以看到当前模块都有哪些依赖。 3.点击 后选择第一个 4.找到你安装IDEA的文件夹,进入到IntelliJ IDEA 2018.3.4\lib目录下…

18.java openCV4.x 入门- Imgproc之色彩映射及颜色空间转换

专栏简介 💒个人主页 📰专栏目录 点击上方查看更多内容 📖心灵鸡汤📖我们唯一拥有的就是今天,唯一能把握的也是今天建议把本文当作笔记来看,据说专栏目录里面有相应视频🤫 🧭文…

kvm虚拟机磁盘镜像加密

一、qcow2的aes加密 低版本的qemu能够支持对qcow2文件进行aes加密的方式,例如对一个已经存在的磁盘文件test.qcow2,可以将其转换为经过加密的qcow2文件。 qemu-img convert -O qcow2 --object secret,idsec0,data123456 -o encryptionon,encrypt.key-s…

为数据穿上安全的外衣——零售电商场景下的数据安全体系建设

在电子商务交易过程中,会涉及大量的个人和财务数据的传输和处理,随着电子商务的发展,数据安全风险也成为一个备受关注的问题。 而跨境电商,属于出海业务,涉及到海外不同国家的政策法规,且数据作为电商的业…

linux安装texlive程序

tex 是文本格式渲染语言, 对数学公式特别友好,所以前沿的科研者基本都要掌握 tex 基本功。Latex 是一款优秀的tex渲染程序,可以直接输出PDF等格式文件。 texlive 是 Latex程序及其周边的一个非常优秀的程序管理包,随着社区的发展…

【InternLM 实战营第二期-笔记4】XTuner 微调个人小助手认知

书生浦语是上海人工智能实验室和商汤科技联合研发的一款大模型,很高兴能参与本次第二期训练营,我也将会通过笔记博客的方式记录学习的过程与遇到的问题,并为代码添加注释,希望可以帮助到你们。 记得点赞哟(๑ゝω╹๑) XTuner 微调个人小助手…

计算机网络之同轴电缆,集线器,网桥,交换机,路由器

ping的过程 两台主机用交叉线连接,通过88.2ping88.3发现底层是先经过广播,通过arp协议,告诉我要找的ip是88.3,然后88.3主机收到后就把自己的mac地址发送回去,同理88.2发现是发给自己的后就进行接收,有了mac地址然后再通…

56、巴利亚多利德大学、马德里卡洛斯三世研究所:EEG-Inception-多时间尺度与空间卷积巧妙交叉堆叠,终达SOTA!

本次讲解一下于2020年发表在IEEE TRANSACTIONS ON NEURAL SYSTEMS AND REHABILITATION ENGINEERING上的专门处理EEG信号的EEG-Inception模型,该模型与EEGNet、EEG-ITNet、EEGNex、EEGFBCNet等模型均是专门处理EEG的SOTA。 我看到有很多同学刚入门,不太会…

C#学习:初始类与名称空间

本节内容: 1.初始类(class)与名称空间(namespace) 这个定义过于复杂。 类(class)构成程序的主体。具体的解释很复杂,要资深开发人才能看的懂,我们先记住这句话。 什么…

视频评论ID提取工具|视频关键词评论批量采集软件

视频评论ID提取工具:批量抓取视频评论 视频评论ID提取工具是一款功能强大的软件,可以帮助您批量抓取视频视频下的评论信息。通过输入关键词和评论监控词,即可进行评论的抓取,并提供评论昵称、评论日期、评论内容、命中关键词以及所…

【Qt】:对话框(一)

对话框 一.基本的对话框二.自定义对话框三.通过图形化界面自定义对话框四.关于对话框mode 对话框是GUI程序中不可或缺的组成部分。一些不适合在主窗口实现的功能组件可以设置在对话框中。对话框通常是一个顶层窗口,出现在程序最上层,用于实现短期任务或者…

腾讯云人脸服务开通详解:快速部署,畅享智能体验

请注意,在使用人脸识别服务时,需要确保遵守相关的法律法规和政策规定,保护用户的合法权益,并依法收集、使用、存储用户信息。此外,腾讯云每个月会提供一定次数的人脸识别调用机会,对于一般的小系统登录来说…

[StartingPoint][Tier2]Included

LXD https://www.hackingarticles.in/lxd-privilege-escalation/ Task 1 What service is running on the target machine over UDP? (目标机器上通过UDP运行的服务是什么?) $ nmap -sU 10.129.232.86 -p 69 tftp Task 2 What class o…

C++:构造函数、析构函数、拷贝构造函数

hello,各位小伙伴,本篇文章跟大家一起学习《C:构造函数、析构函数、拷贝构造函数》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 如果本篇文章对你有帮助,还请各位点点赞…