Java环形链表(图文详解)

news2024/11/28 4:41:57

目录

一、判断链表中是否有环

(1)题目描述

(2)题解

二、环形链表的入环节点

(1)题目描述

(2)题解


一、判断链表中是否有环

(1)题目描述

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

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

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

示例:

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

输出:true(节点有环)

(2)题解

思路分析:我们可以使用快慢指针来分析这个问题。

1.首先定义fast、slow指向head

2.快指针fast一次走两步、慢指针slow一次走一步

3.如果链表中无环,fast最终会指向null,若链表中有环,在fast和slow都进入环中后,由于fast每次比slow多走一步,fast最终会追上slow

代码实现:

public class Solution {
    public boolean hasCycle(ListNode head) {
        //先判断特殊情况
        //若链表中为空或链表中只有一个元素,
        // 则链表中无环
        // 直接返回false
        if (head == null || head.next == null) {
            return false;
        }
        //定义快指针和慢指针
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;//fast一次走两步
            slow = slow.next;//slow一次走一步
            if (fast == slow) {//fast与slow相遇,表明链表带环
                return true;
            }
        }
        //fast指向空或指向尾节点,表明链表不带环
        return false;
    }
}

思考:

1. while条件中,能否修改为 while(fast.next != null && fast != null) ?

不能,&&(逻辑与)操作符从左到右进行判断,当左边为false时,右边的表达式不会进行运算,直接返回false,只有当左边表达式为true时,才会运算右边的表达式,若右边表达式为true,则返回true

在while条件中,应先判断fast的指向是否为空,若fast的指向为空,则不能够通过fast.next访问下一个节点,否则会抛出NullPointerException(空指针异常)。因此,while (fast != null && fast.next != null),当fast指向null时,直接返回false,而不再执行fast.next

2. 当fast走两步,slow走一步时,fast能够追上slow,当fast走三步、四步...时能否追上slow ?

当链表无环时,fast走两步、三步...都能判断链表无环

当链表有环时,我们假设fast每次走 x ( x >= 2 )步,head到入环节点有a个节点(从head到入环节点需要走a步),环上一共有C个节点,当slow走到入环节点时,fast与slow相距N0 <= N < C)个节点

当N = 0时,fast与slow直接在入环节点相遇,因此我们考虑N > 0 且 N < C 的情况

当slow走到入环节点时,此时就是我们常说的追及问题,追及问题的公式:

追及时间(次数) = 路程差 / 速度差

我们设追及次数(即fast走多少次追上slow)为m,fast与slow之间的路程差为N,速度差为x-1,则m = N / x-1,

当x = 2时,m = N,即fast走N次就能追上slow,

当x = 3时,m = N / 2,当N为偶数时,fast 走N/2次能够追上slow;当N为奇数时,fast走了(N-1)/ 2次之后,此时fast与slow的距离为1,由于fast走三步,slow走一步,fast会反超slow 1 步

此时fast与slow的距离N变为C-1,fast重新开始追及slow,若C-1为偶数,则经过 (C-1)/2次后,fast追上slow;若C-1为奇数,在fast与slow距离为1时,fast再次反超slow,fast与slow之间的距离再次变为C-1,fast再次追及slow...如此循环,fast永远追不上slow

 因此,我们可以看出,当fast一次走三步,slow一次走一步时,fast不一定能追上slow

当fast一次走四步,slow一次走一步时,分析思路与fast一次走三步一致,fast可能反超slow一步或两步,此时fast与slow的距离变为C-1 或 C-2,然后继续分情况分析

3.当fast走三步,slow走两步,或是fast走四步,slow走三步时,情况又如何呢 ?

由追及时间(次数) = 路程差 / 速度差,可以得出

当fast走三步,slow走两步 或是 fast一次走四步,slow一次走三步,fast与slow的速度差都为1,fast一定能追上slow,但

当fast一次走两步,slow一次走一步,slow走的总路程为N,即fast在一圈以内,能够追上slow

而当fast一次走三步,slow一次走两步时,slow走的总路程为2*N(2*N可能大于C),因此fast不一定在一圈之内追上slow

本题来自:

141. 环形链表 - 力扣(LeetCode)

二、环形链表的入环节点

(1)题目描述

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

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

示例

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

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

(2)题解

思路分析:在判断链表是否有环中,我们使用快慢指针的方法来判断链表中是否有环。fast一次走两步,slow一次走一步,若链表有环,fast一定能在环中追上slow。基于这个结论,我们可以继续推出另一个结论:从头节点出发的指针会和从fast、slow相遇节点出发的指针相遇与入环节点(证明在最后)

因此,找到入环节点:

1.判断链表是否有环,无环返回null,有环找到fast与slow相遇的节点

2.让两个指针,分别从头节点、相遇点出发,当两指针汇合时,即为链表的入环节点

代码实现:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        //链表为空,直接返回null
        if(head == null){
            return null;
        }
        ListNode fast = head;
        ListNode slow = head;
        while(fast.next != null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
            //找到fast与slow的相遇点
            if(fast == slow){
                //让fast从头节点出发,
                //slow从相遇点出发,
                fast = head;
                while(fast != slow){
                    fast = fast.next;
                    slow = slow.next;
                }//相遇节点即为入环节点
                     return slow;
            }
        }
        //链表中无环,返回null
        return null;
    }
}

为何从头节点出发的指针一定会和从fast、slow相遇节点出发的指针汇合与入环节点?

同样,当链表有环时,我们假设head到入环节点有a个节点(从head到入环节点需要走a步),环上一共有C个节点,fast与slow相遇时,与入环节点的距离为d

当fast与slow相遇时,

fast所走的路程为 a + n*C + d

fast所走路程为什么是a + n*C + d?

a为从头节点到入环节点的距离,当a > C时,可能slow还未进环,而fast已经在环中走了很多圈了,我们假设当fast与slow相遇时,fast在环中走了n圈,因此fast所走的路程为a + n*C + d

slow所走的路程为 a + d

由于fast的速度是slow的两倍,因此

2*(a + d)= a + n*C + d,即 a = n*C - d

将n*C化为 C*(n-1) + C,式子可化为 a =C* (n-1) + C-d

a是从头节点到入环节点的距离,C - d 是 相遇节点距入环节点的距离,

a =C* (n-1) + n-d 表明,从头节点出发的指针走 a步 等于 从相遇节点开始走的指针,走(n-1)圈后回到相遇点,再走n - d的距离,即从头节点出发的指针和从fast、slow相遇节点同时出发的指针最终会在入环节点处相遇

题目来自:

142. 环形链表 II - 力扣(LeetCode)

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

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

相关文章

OCX 添加方法和事件 HTML调用ocx函数及回调 ocx又调用dll VS2017

ocx添加方法 类视图 最后面的XXXXXlib 右键 添加 添加方法。 其它默认 添加事件 类视图 最后面的XXXXX 右键 添加 添加事件。 这样编译就ocx可以了。 #include <iostream> #include <string> #include <comutil.h>CMFCActiveXControlSmartPosCtrl* …

Linux内核启动流程-第二阶段rest_init函数

一. Linux内核启动 上一篇文章简单了解了 Linux内核启动第二阶段&#xff0c;涉及的 start_kernel函数。start_kernel 函数最后调用了 rest_init 函数&#xff0c;接下来简单看一下 rest_init 函数。 本文续上一篇文章的学习&#xff0c;地址如下&#xff1a; Linux内核启…

W5500+树莓派RP2040入门教程之MQTT篇(十二)

目录 1 前言 2 什么是MQTT协议&#xff1f; 2.1 特点 2.2 应用 2.3 身份 2.4 消息质量等级 2.5 遗嘱消息 3 硬件介绍 4 硬件接线 5 代码编写 6 移植说明 7 最终现象 8 总结 9 项目链接 1 前言 随着物联网技术的快速发展&#xff0c;MQTT&#xff08;Message Queuing Telemetry …

微分算子法求解常系数线性微分方程特解

1.微分算子法求解常系数线性微分方程特解 参考资料&#xff1a;全网讲解最清楚的微分算子法&#xff01; 1.1 微分算子法的思路 1.2 f ( x ) e α x f(x)e^{\alpha x} f(x)eαx 型 1.3 f ( x ) sin ⁡ β x f(x)\sin\beta x f(x)sinβx 或 f ( x ) cos ⁡ β x f(x)\co…

oracle VM virtualbox 自动挂载共享目录

目标&#xff1a; 1 安装增强插件 2 设置共享目录 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a3ef43aa3a934e4691bad53874f6b427.png 3 修改fstab sudo chmod 777 /etc/fstab vi /etc/fstab 增加一行&#xff1a; pc /mnt/pc vboxsf defaults 0 0 例子&#xff1a…

tensor维度变换

作用函数不变大小改变shapeview / reshape删减与增加维度squeeze / unsqueeze维度扩展expand / repeat矩阵转置&#xff0c;单次和多次交换操作t / transpose / permute 1、 view reshape view与reshape效果一致&#xff0c;且可以通用。直接以view为例&#xff1a; a torc…

CH08_搬迁特性

搬迁函数&#xff08;Move Function&#xff09; 曾用名&#xff1a;搬迁函数&#xff08;Move Method&#xff09; class Account{get overdraftCharge(){...}... }class AccountType{get overdraftCharge(){...}... }动机 模块化是优秀软件设计的核心所在&#xff0c;好的模…

C语言自定义类型讲解:结构体,枚举,联合(2)

&#x1f435;本篇文章将会对位段、枚举和联合的相关知识进行讲解 1. 位段&#x1f4da; 1.1 什么是位段 位段的声明和结构体类似&#xff0c;但是有两点不同&#xff1a; 1.位段的成员必须是int&#xff0c;unsigned int&#xff0c;signed int (C99之后也可以是其他成员&am…

Redis 线程模式

Redis 是单线程吗&#xff1f; Redis 单线程指的是 [接收客户端请求 -> 解析请求 -> 进行数据读写操作 -> 发送数据给客户端] 这个过程是由一个线程 (主线程) 来完成的&#xff0c;这也是常说的 Redis 是单线程的原因。 但是 &#xff0c;Redis 程序不是单线程的&am…

nginx 反向代理 负载均衡 动静分离

一样东西的诞生通常都是为了解决某些问题&#xff0c;对于 Nginx 而言&#xff0c;也是如此。 比如&#xff0c;你出于无聊写了一个小网站&#xff0c;部署到 tomcat 之后可以正常访问 但是后来&#xff0c;你的这个小网站因为内容很诱人逐步的火了&#xff0c;用户越来越多&a…

C#开发的OpenRA游戏之雷达地图

C#开发的OpenRA游戏之雷达地图 从前面的游戏里,就可以看到在上面按钮下面留有一个区域,这个区域的作用,就是用来显示一个雷达地图,如下图所示: 从雷达地图来看,可以清楚地看到全局的动态,自己的兵力分布,还有自己的建筑分布,矿产分布等等。 在这里就来对这个雷达地图…

Python编程:使用PIL进行JPEG图像压缩的简易教程

摘要: 本文介绍了如何使用Python编程语言和wxPython图形用户界面库进行JPEG图像的压缩。通过添加滑块控件&#xff0c;我们可以调整压缩质量&#xff0c;并将压缩后的照片另存为原来的名称加上后缀"压缩质量数字"的新文件。 C:\pythoncode\new\image2small.py 完整…

AI编程助手 Amazon CodeWhisperer 全面解析与实践

目录 引言Amazon CodeWhisperer简介智能编程助手智能代码建议代码自动补全 提升代码质量代码质量提升安全性检测 支持多平台多语言 用户体验和系统兼容性用户体验文档和学习资源个性化体验系统兼容性 功能全面性和代码质量功能全面性代码生成质量和代码安全性 CodeWhisperer的代…

程序启动-大数据平台搭建

1、启动zookeeper集群 /home/cluster/zookeeper.sh start /home/cluster/zookeeper.sh stop 2、启动hadoop和yarn集群 /home/cluster/hadoop-3.3.6/sbin/start-dfs.sh /home/cluster/hadoop-3.3.6/sbin/start-yarn.sh /home/cluster/hadoop-3.3.6/sbin/stop-dfs.sh /home/clust…

以太坊代币标准ERC20、ERC165、ERC721

两个概念 ERC(Ethereum Request for Comment) 以太坊意见征集稿EIP(Ethereum Improvement Proposals)以太坊改进提案 ERC和EIP用于使得以太坊更加完善&#xff1b;在ERC中提出了很多标准&#xff0c;用的最多的标准就是它的Token标准; 有哪些标准详细见https://eips.ethereum…

预制菜行业数据分析(京东数据挖掘)

最近一段时间&#xff0c;关于预制菜进校园事件的讨论热度高涨。而这两天&#xff0c;核酸大王“张核子”转行开预制菜公司卖方便米饭的消息又被传出&#xff0c;直接让预制菜市场饱受关注。 “预制菜是近两年的风口”&#xff0c;这个结论鲸参谋早在以往的内容中专门讨论过&a…

Java 18的未来:新特性和编程实践

文章目录 引言新特性预览1. 基于值的类的进一步改进2. 模式匹配的增强3. 新的垃圾回收器4. 扩展的模块系统5. 更强大的异步编程 编程实践示例1&#xff1a;基于值的类示例2&#xff1a;模式匹配的增强示例3&#xff1a;新的垃圾回收器 结论 &#x1f389;欢迎来到Java学习路线专…

python机器学习融合模型:Stacking与Blending(附代码)

1 堆叠法Stacking 一套弱系统能变成一个强系统吗&#xff1f; 当你处在一个复杂的分类问题面前时&#xff0c;金融市场通常会出现这种情况&#xff0c;在搜索解决方案时可能会出现不同的方法。 虽然这些方法可以估计分类&#xff0c;但有时候它们都不比其他分类好。在这种情况…

[WUSTCTF2020]颜值成绩查询 布尔注入二分法

这道题很简单 就是sql注入 我们来学习一下如何写盲注脚本 ?stunum1 ?stunum123 正确回显 100 错误 显示 not 。。。 这里很显然就是盲注了 我们来写个语句查询 if(ascii(substr(database(),1,1))>1,1,0)发现回显了 我们可以开始编写脚本跑了 import requests impor…

DeepMind 利用无监督学习开发 AlphaMissense,预测 7100 万种基因突变

类基因组共有 31.6 亿个碱基对&#xff0c;无时无刻不在经历复制、转录和翻译&#xff0c;也随时有着出错突变的风险。 错义突变是基因突变中的一种常见形式&#xff0c;然而人类目前只观察到了其中的一小部分&#xff0c;能够解读的更是只有 0.1%。 准确预测错义突变的作用&am…