判断环形链表是否有环??返回环形链表的入口点!!

2023-11-01

上次笔者写了一篇大概有7个题的链表相关的题目+解析,感觉还不错,感兴趣的各位老铁,可以点一下链接进行欣赏:做几个与链表相关的题吧https://blog.csdn.net/weixin_64308540/article/details/128550685?spm=1001.2014.3001.5502那么,接下来就该进入:环形链表部分了!!

141. 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false

示例 1:

输入:head = [3,2,0,-4], pos = 1

输出:true

解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0

输出:true

解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1

输出:false

解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]

  • -105 <= Node.val <= 105

  • pos 为 -1 或者链表中的一个 有效索引

进阶:你能用 O(1)(即,常量)内存解决此问题吗?

上述是力扣中的题目!如果你已经看完了题目,那么,就该跟着笔者进入正文解析了!!

根据链表的基础知识,我们可以得出:如果一个链表是环形链表,那么最后一个节点一定存储了前面某个节点的地址!!

思路:快慢指针:

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表的起始位置(头节点)开始进行,如果链表带环,则快指针与慢指针一定会在环中相遇!!否则,快指针一定会率先走到链表的尾部,比如,陪女朋友到操场跑步减肥!!

扩展问题:

  1. 为什么快指针一次走两步,慢指针一次走一步可以??

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

2.快指针一次走3步,走4步,...n步行吗? 假设有环的情况下:快指针每次走3步,慢指针每次走1步,此时快指针肯定先进环,慢指针后来才进环,假设慢指针进环的时候,快慢指针的相对位置如图所示:

此时按照上述的假设:快指针每次走3步,慢指针每次走1步,来绕环移动,是永远不会相遇的!!此时进行了套圈!!

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

此时我们可以看出,环的问题,可以大致理解为:追及相遇的问题!!

那么,有了这些想法,我们还应该判断没环的情况下的问题:

经过上述的分析,我们可以看出当没环条件下的结束条件!

因此,我们有着下述的简单代码:写法1:

 public boolean hasCycle(ListNode head){
        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;
    }

写法2:

    public boolean hasCycle2(ListNode head){
        ListNode fast=head;
        ListNode slow=head;
        while (fast != null && fast.next !=null){
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){
                break;//出while循环(有两种可能)
            }
        }
        if (fast==null ||fast.next==null){//排除不是环的可能
            return false;
        }
            return true;       
    }

经过这个题目,我们可以思考一下,如何进行手动置环??

手动置环问题:遍历一遍链表,找到尾巴节点,其所对应的next本为null,将其改为前面任意节点的地址就可以了(保证有)!!

   //手动置环
    public void creatLoop(ListNode head){
        ListNode cur=head;
        while (cur.next !=null){
            cur=cur.next;//找尾巴节点
        }
        cur.next=head.next.next;//保证有该节点!
    }
142. 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1

输出:返回索引为 1 的链表节点

解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0

输出:返回索引为 0 的链表节点

解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1

输出:返回 null

解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内

  • -105 <= Node.val <= 105

  • pos 的值为 -1 或者链表中的一个有效索引

进阶:你是否可以使用 O(1) 空间解决此题?

对于这个题目,显得有点儿难度!!

结论 让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。 证明

这个是主要的思路,或许你看不懂,没关系,那么请看一下笔者的推论吧!!

我们有着以下的简单思路:

  1. 当在最好的情况下:我们有着:fast多走一圈,然后与slow在相遇处相遇,此时,fast走的路程为:X+C(C-Y)  此时,slow走的路程:X+(C-Y),由于fast的速度是slow的二倍,则路程也是2倍,即有着一下结论:2*(X+C-Y)=X+C+(C-Y)  经过计算,我们可以得到;X==Y

  1. 当不最好的情况下:fast走了很多圈,才与slow在相遇点相遇,此时说明,环的长度C很小很小!!

此时,fast走的路程为:X+NC(C-Y) 此时,slow走的路程:X+(C-Y),由于fast的速度是slow的二倍,则路程也是2倍,即有着一下结论:2*(X+C-Y)=X+NC+(C-Y) 经过计算,我们可以得到;X==(N-1)*C+Y 因此,当N很大很大的时候,说明环很小很小了,而fast多走的长是从相遇点开始的!

注意:

  1. 当慢指针进入环时候,快指针可能已经在环中绕了N圈了,N至少为1,因为当快指针先到环走到相遇点的位置,慢指针还没有进环!

  1. 慢指针进入环以后,快指针肯定会在慢指针走一圈之内追上慢指针,因为:快指针进环之后,快慢指针之间的距离最多就是环的长度,而两个指针在移动的时候,每次他们之间的距离都会缩减1步,因此,慢指针移动一圈之前,快指针一定可以追上慢指针的!!

下面请看笔者的代码吧!!代码起很简单,但是思路很重要!!

  //返回循环链表的相交节点
    public ListNode detectCycle(ListNode head){
        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;//将fast或者slow任意一个拉回头节点head
        while (fast !=slow){
            fast=fast.next;
            slow=slow.next;
        }//当fast与slow再次相遇的时候,即为入口点
        return fast;
    }

对于这个代码,想必各位老铁都能看懂吧!!

由于在码字的过程中,出现了些许差错,导致有点错别字!!勿怪!勿怪!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

判断环形链表是否有环??返回环形链表的入口点!! 的相关文章

  • .bss段和.data段

    BSS段 BSS段 bss segment 通常是指用来存放程序中未初始化的或者初始值为0的全局变量的一块内存区域 BSS是英文Block Started by Symbol的简称 BSS段属于静态内存分配 数据段 数据段 data seg

随机推荐

  • 科目二练习总结

    第一次 方向盘课程 第二次 基础课程 上车先调座椅 垫坐垫 头部离顶部一拳 后背调整 舒服的姿势 不能太打直 座椅前后调整 离合踩到底 脚不是伸直的 膝盖离车体一拳 调后视镜 右手边上圆形 有L R的就是调整的 L 左视镜 后门把手在镜头3
  • JAVA实现图片质量压缩和加水印

    这个世界没有什么好畏惧的 反正我们只来一次 文章目录 前言 编写代码 1 编写工具类 2 编写接口 3 测试接口 总结 前言 主要实现了两个功能 加水印 质量压缩 编写代码 1 编写工具类 ImageUtil代码如下 package com
  • ceph中的Pools、PGs和OSDs介绍(tmp)

    2019独角兽企业重金招聘Python工程师标准 gt gt gt How are Placement Groups used A placement group PG aggregates objects within a pool be
  • Python-栈结构

    栈 stack 又名堆栈 它是一种运算受限的线性表 栈只能在一端进行插入和删除操作 它按照先进后出 FILO 的原则存储数据 先进入的数据被压入栈底 最后的数据在栈顶 栈也可以看成是 FILO 的队列 class Stack object
  • String类常用方法

    红色为常用的方法 1 和长度有关的方法 得到一个字符串的字符长度 String s abc s length 2 和数组有关的方法 返回类型 方法名 作用 byte getBytes 将一个字符串转换成字节数组 char toCharArr
  • mysql对表中列的操作_mysql对表基本操作

    一 对表的操作 1 添加新的字段 alter table 表名 add name varchar 20 2 删除表中已有的字段 alter table 表名 drop name 3 修改表中已有的字段 alter table 表名 chan
  • js 计算两个日期之间的相差的天数

    将两个日期都转换为毫秒相减后 将减下来的毫秒数转换为天数 就可以得到两个日期之间相差的天数了 接受的日期格式为 2023 1 31 2023 2 28 的日期字符串 const getDaysApart date val date vals
  • ubuntu下jmxtrans 安装

    JAVA 监控内容收集之 Jmxtrans 它是一个为应用程序 设备 系统等管理功能的框架 通常可以用来监控和管理Java应用系统 1 拷贝jmxtrans至LS1上 scp jmxtrans 251 deb LS1 2 安装jmxtran
  • Google Chrome在Windows7安装离线版

    前言 今天因为旧版chrome老是要报更新 所以安装了个新版 因为被墙原因 许多网友会遇到一些安装chrome的问题 所以今天分享一下安装教程 安装chrome 1 前往chrome官网 可以看到链接地址是http www google c
  • 如何构造测试数据

    前言 我这里只是专注于生成CSV等测试数据文件 每次构造测试数据的时候就很头疼 之前自己简单造个两三行还行 造多了就有些费脑细胞了 抽出些时间来专门找一下有没有相应工具 小数据量测试数据 小数据量测试数据使用在线的网站就行 10W以内的数据
  • 【Python】使用Python根据BV号爬取对应B站视频下的所有评论(包括评论下的回复)

    Python 使用Python根据BV号爬取对应B站视频下的所有评论 包括评论下的回复 本文写于2020 4 27 当你阅读到本文的时候如果因为下列原因导致本文代码无法正常工作 本人概不负责 B站的页面和API接口的变动 B站为页面和API
  • 操作系统笔记(手写)

    前言 这学期开始学习计算机网络 操作系统和Java程序设计 这些课的重要性不言而喻 对于我这种纯粹的小白来说 压力真得很大 自己水平有限 领悟能力较差 学习接受能力很慢 不知道怎样才能真真的学懂 学会这些东西 所以就先跟着学校安排的网课和配
  • 常见的数据结构与算法

    文章目录 前言 一 常见的数据结构 1 数组 2 链表 3 栈 4 队列 5 树 二 排序 1 基本的排序算法 2 常考的排序算法 3 其他排序算法 三 递归与回溯 1 递归 2 回溯 四 深度与广度优先搜索 1 深度优先搜索 2 广度优先
  • 伴随矩阵介绍及C++实现

    在线性代数中 一个方形矩阵的伴随矩阵是一个类似于逆矩阵的概念 如果矩阵可逆 那么它的逆矩阵和它的伴随矩阵之间只差一个系数 然而 伴随矩阵对不可逆的矩阵也有定义 并且不需要用到除法 设R是一个交换环 在抽象代数之分支环论中 一个交换环 com
  • 【vue】vue子孙组件传值(多级嵌套)attrs listeners

    如果vue开发遇到多层嵌套 子孙组件之间传值 可以使用 attrs listeners传值 示例如下 孙子组件
  • 装上这10个插件,PyCharm才是无敌的存在

    pycharm是一款强大的python集成开发环境 带有一整套python开发工具 今天就给大家介绍几款非常好用的插件 首先插件的下载方法 进入File gt Settings gt Plugins 根据需要搜索插件名称 记得是在Marke
  • db是哪个城市的缩写_全国所有城市拼音及缩写

    北京 BEIJING BJ 上海 SHANGHAI SH 天津 TIANJIN TJ 重庆 CHONGQING ZQ 阿克苏 AKESU AKS 安宁 ANNING AN 安庆 ANQING AQ 鞍山 ANSHAN AS 安顺 ANSHU
  • 分享一款开源堡垒机-jumpserver

    JumpServer是由FIT2CLOUD 飞致远 公司旗下一款开源的堡垒机 这款也是全球首款开源的堡垒机 使用 GNU GPL v2 0 开源协议 是符合 4A 规范的运维安全审计系统 使用 Python 开发 遵循 Web 2 0 规范
  • java basefont_itext 文本域 字体样式设置

    使用acroFields setFieldProperty nameField textfont baseFont null 的方式不能加粗 因为第三个参数必须是BaseFont类型 不能是Font类型 可以使用下面的方式加粗 BaseFo
  • 判断环形链表是否有环??返回环形链表的入口点!!

    上次笔者写了一篇大概有7个题的链表相关的题目 解析 感觉还不错 感兴趣的各位老铁 可以点一下链接进行欣赏 做几个与链表相关的题吧 https blog csdn net weixin 64308540 article details 128