关于如何找环形链表的入环点

news2024/9/30 23:36:16

目录

  • 一、判断一个链表是否有环
  • 二、找到链表入环的第一个节点

一、判断一个链表是否有环

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题思路:

用快慢指针,慢指针一次往后走一步,快指针一次往后走两步。这样快指针会比慢指针先入环,当慢指针入环被快指针追上时,说明这是一个环形链表,当快指针为空或者指向空时,说明这不是环形链表,返回NULL。

在这里插入图片描述
为什么肯定slow 和 fast一定会相遇呢?我们假设当slow入环时,fast到slow的距离为N。
在这里插入图片描述
而slow 每次往前走一步,fast 每次往前走两步,那么它们的距离是逐渐递减的。
在这里插入图片描述
最后它们之间的距离为 0 时,它们就相遇了。

那问题来了,如果fast 一次走三步,四步,五步,它能不能在环中与slow相遇呢? 我们假设fast一次走三步。
fast到slow的距离继续为N
在这里插入图片描述

slow 一次走一步, fast一次走三步 , 那么N是每次少2
在这里插入图片描述
此时会出现两者情况,一种情况是相遇了,还有一种情况是没相遇。
当没相遇的时候,fast已经跑到了 slow的前面,也就是它们此时的距离是-1。
在这里插入图片描述
设这个环的长度为C,所以它们的距离 N 此时是等于 C-1的。而因为fast一次是走三步的,所以N每次会-2。 当N等于0时它们才会相遇,这也就意味,C-1 如果是偶数,那么它们才会相遇,如果C-1 是奇数,那它们永远不会相遇。所以,fast 一次走两步,它一定会和slow在环里面相遇,slow不用走完一圈。如果fast一次走3,4,5…n步,那么是有可能永远不会与slow相遇的。

代码如下:

bool hasCycle(struct ListNode *head) {
    struct ListNode* slow = head;
    struct ListNode* fast = head;

    //如果fast为空或者指向空,说明不是环形链表
    while(fast && fast->next)
    {
        //慢指针一次走一步,快指针走两步
        fast = fast->next->next;
        slow = slow->next;

        //如果fast 与 slow 相遇,说明是环形链表
        if(fast == slow)
        {
            return true;
        }
    }
    //出了循环,说明不是环形链表
    return false;
}

题目链接

二、找到链表入环的第一个节点

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

判断了一个链表是否有环之后,那么如何找到链表入环的第一个节点呢?我们设链表头节点到入环的第一个节点为L。
在这里插入图片描述
我们再设 入环的第一个节点,到slow 与fast相遇的节点的距离为X。
在这里插入图片描述
那么slow 走的距离是 L + X
设圆的长度为C
那么fast走的距离是 L + NC + X
N代表走的圈数,因为当环长度很小,而L长度非常大的时候,slow 入环时,fast 不可能只走一圈,一圈是极端情况,这样我们就可以推导出。
2(L + X ) = L + N
C +X
L + X = N * C
L = N * C - X
L = (N-1) *C + C - X
而N - 1 是 fast走的圈数,我们可以省掉
所以 L = C - X
在这里插入图片描述
代码:

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow , *fast;
    slow = fast = head;
    while(fast && fast->next)
    {
       
        fast = fast->next->next;
        slow = slow->next;

         if(fast == slow)
        {
            //保存相遇节点
            struct ListNode* MeetNode = slow;
            struct ListNode* NewHead = head;
            //相遇点和头节点同时走
            while(MeetNode != NewHead)
            {
                MeetNode =  MeetNode->next;
                NewHead =   NewHead->next;
            }
            return MeetNode;
        }
    }
    return NULL;
}

当然,这题还有第二种方法,不过容易理解,实现起来可能有点困难。
我们可以把相遇节点的下一个节点,作为一个新链表的头节点,而上一个节点作为两个链表的尾节点。而这俩个相交的节点,就是入环的第一个节点
在这里插入图片描述
至于如何找到两个链表的交点,上一篇博客第八题有说明,传送地址

所以第二种方法,我们只需要找到它们的newhead和head的相交节点就可。

代码

struct ListNode *detectCycle(struct ListNode *head) {
        struct ListNode* slow , *fast;
        slow = fast = head;

        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;

            //如果俩节点相遇
            if(slow == fast)
            {
                //新节点为相遇的下一个节点
                struct ListNode* NewHead = slow->next;
                struct ListNode* OldHead = head;
                //求出新节点 和 原头节点 到 尾节点(slow)的长度 
                int lenNew = 1;
                int lenOld = 1;
                while(NewHead != slow)
                {
                    NewHead = NewHead->next;
                    lenNew++;
                }

                while(OldHead!= slow)
                {
                    OldHead = OldHead->next;
                    lenOld++;
                }
                //相差多少个长度
                int gap = abs(lenOld - lenNew);
                //找到较长和较短的链表
                struct ListNode* LongList = head;
                struct ListNode* ShortList = slow->next;
                if(lenOld < lenNew)
                {
                    LongList = slow->next;
                    ShortList = head;
                }
                //让长节点先走gap次
                while(gap--)
                {
                    LongList = LongList->next;
                }
                //然后俩个节点同时走
                while(LongList != ShortList)
                {
                    LongList = LongList->next;
                    ShortList = ShortList->next;
                }
                //此时就是相交节点
                return ShortList;
            }

        }
    return NULL;
}

题目链接

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

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

相关文章

菇多糖-聚乙二醇-大环配体NOTA,大环配体NOTA-PEG-香菇多糖

菇多糖-聚乙二醇-大环配体NOTA&#xff0c;大环配体NOTA-PEG-香菇多糖 中文名称&#xff1a;香菇多糖-大环配体NOTA 英文名称&#xff1a;Lentinan-NOTA 别称&#xff1a;NOTA修饰香菇多糖&#xff0c;NOTA-香菇多糖 PEG接枝修饰香菇多糖 Lentinan-PEG-NOTA 香菇多糖-聚乙…

设置Excel表格“只读模式”的两种方法

Excel表格的“只读模式”可以帮助我们防止意外更改表格&#xff0c;根据不同需求&#xff0c;表格可以设置“有密码”和“无密码”的两种“只读模式”&#xff0c;下面来说说具体设置方法。 一、无密码“只读模式” 如果主要是想防止自己意外修改了表格&#xff0c;可以设置没…

Jenkins拉分支代码 + tortoiseGit删除分支

日常部署测试代码都使用Jenkins代码手工上传代码&#xff0c;主要减减减减工作量&#xff0c;提高工作效率&#xff1b; 一、安装Git、git-parameter插件及配置方法&#xff0c;安装方法忽略一万字&#xff0c;解决不了绕道度娘问问 二、创建项目&#xff0c;设置参数 This pr…

[操作系统笔记]基本分页存储管理

内容系听课复习所做笔记&#xff0c;图例多来自课程截图 基本分页存储管理 两次访存&#xff0c;第一次查页表&#xff0c;第二次访问目标内存单元 将内存空间分为一个个大小相等的分区&#xff08;比如每个分区4KB&#xff09;&#xff0c;每个分区就是一个“页框”&#xff0…

[附源码]计算机毕业设计springboot物业管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

澜沧古茶在港交所上市申请失效:收入不及八马茶业,股东提前套现

12月1日&#xff0c;贝多财经从港交所披露易了解到&#xff0c;普洱澜沧古茶股份有限公司&#xff08;下称“澜沧古茶”&#xff09;的上市申请材料失效&#xff0c;目前已无法正常查看或下载。据贝多财经了解&#xff0c;“失效”并不意味着上市失败。 事实上&#xff0c;招股…

selnium操作输入框无法输入内容

问题描述 分析问题 1、开始以为等待时间问题没有找到元素&#xff08;没解决&#xff09; 2、使用js操作元素&#xff08;没解决&#xff09; 3、定位到光标元素 4、种cookie直接走接口调用 问题描述 selenium.common.exceptions.ElementNotInteractableException: Mess…

企业数据图表- FineReport函数计算组成和语法概述

1. 概述 1.1 版本 1.2 功能简介 在设计模板时用户需要频繁的使用公式函数&#xff0c;例如&#xff1a;求和、求个数、做判断等等。 本文介绍函数的计算组成和语法。 2. 计算语法 2.1 概览 组成部分 语法 示例 函数 SUM(合同金额)、SUM(A1) 数据列 可输入有数据列的…

基于Vue+nodejs+Element-ui的聊天框项目

目录一、项目简介二、环境介绍三、系统展示四、视频功能展示五、前端核心代码展示六、MySQL 数据库创建功能展示七、node.js 核心代码八、总结一、项目简介 本项目基于纯前端&#xff08;移动端&#xff09;技术开发一个聊天系统&#xff0c;界面美观大方&#xff0c;采用Node…

PowerShell禁止运行脚本

运行脚本报错(pnpm -v) pnpm : 无法加载文件 D:\win11\program\NVM\nodejs\pnpm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 https:/go.mi crosoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 所在位置 行:1 字符: 1pnpm -v…

洛谷千题详解 | P1019 [NOIP2000 提高组] 单词接龙【C++、Java语言】

博主主页&#xff1a;Yu仙笙 专栏地址&#xff1a;洛谷千题详解 目录 题目描述 输入格式 输出格式 输入输出样例 解析&#xff1a; C源码&#xff1a; Java源码&#xff1a; -----------------------------------------------------------------------------------------------…

java+mysql基于SSM共享型汽车租赁系统-计算机毕业设计

项目介绍 共享汽车租赁公司的共享汽车租赁流程复杂、数据庞大&#xff0c;往往一个疏忽就会给公司造成极大的损失&#xff0c;于是越来越多的共享汽车租赁公司需要一个对各项信息的管理平台来避免这样的损失。为了满足这个需求&#xff0c;我们开发一个针对共享汽车租赁信息的…

MR直播实例(混合现实直播)高品质企业直播

阿酷TONY / 2022-12-2 / 长沙 / 超多组图 绿幕抠像 虚拟场景&#xff08;三维场景&#xff09;实时渲染&#xff0c;降低直播成本&#xff0c;带来线下活动所没有的沉浸式视听体验。 虚拟舞台场景介绍参见&#xff1a; 企业年会直播来个虚拟舞台场景如何&#xff1f;_阿…

负载均衡与高可用

目录 负载均衡 理论部分 应用层负载均衡 环境搭建 代理服务器配置 web服务器配置 验证 网络层负载均衡 环境搭建 代理服务器配置 mysql服务器配置 验证 高可用 理论部分 环境搭建 负载均衡高可用 lb1主要服务器配置 lb2备份服务器配置 web配置 验证 nginx故障问题 →→→→ 大虾…

【MySQL】-增删查改

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀学Java的冬瓜&#x1f319; 专栏&#xff1a;MySQL 分享&#xff1a;至若春和景明&#xff0c;波澜不惊&#xff0c;上下天光&#xff0c;一碧万顷。沙鸥翔集&#xff0c;锦鳞游泳&#xff0c;岸芷汀兰&#xff0c;郁郁青青…

傻妞旧版合集新版订阅

目录一、前言二、下载三、新版傻妞订阅合集一、前言 傻妞旧版本(合集),包含amd和arm版本收集于TG 我的是amd架构 [rootecs-mike_note ~]# cat /proc/version Linux version 4.11.8-1.el7.elrepo.x86_64 (mockbuildBuild64F25) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-11…

Vue中的计算属性

计算属性&#xff1a;实际上是把vm中的属性进行计算加工&#xff0c;最后能够返回给页面一个结果 细想一下&#xff0c;其实methods方法也能实现1中描述的现象&#xff0c;但是计算属性最大的优势是缓存&#xff01;&#xff01;&#xff01; 举个例子 <div id"root&q…

【Android App】物联网实战项目之自动驾驶的智能小车(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言私信~~~~ 当今社会正在步入一个万物互联的时代&#xff0c;它的技术基石主要来自5G、物联网和人工智能。 三者融合产生了许多新产品&#xff0c;其中最璀璨的当数自动驾驶的电动车&#xff1b;它汇聚了最新科技与工程实践的成果&#xff0c;…

【收纳】电脑资料-高效整理电脑上的文件

以前没想过整理文件&#xff0c;一般都是建各种文件夹&#xff0c;然后把资料拖进去&#xff0c;好像收起来了&#xff0c;但实际是随着文件越来越多&#xff0c;时间一久&#xff0c;经常找不到文件&#xff1b;后来逐渐意识到&#xff0c;需要改变。于是找了很多方法&#xf…

已分区的硬盘如何重新合并, 分出去的盘怎么重新合并

已分区的硬盘如何重新合并&#xff1f;磁盘分区后合区是指对原磁盘的分区进行合并&#xff0c;使之成为一个的磁盘分区&#xff0c;从具体的应用层面来分析&#xff0c;为什么会对磁盘分区后合区呢&#xff1f; 磁盘管理对磁盘分区后合区 在Windows系统中&#xff0c;磁盘管理…