链表经典OJ问题【环形链表】

题目导入

题目一:给你一个链表的头节点 head ,判断链表中是否有环
题目二:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL。

题目一

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

分析

这里我们不能用单个指针来判断是否带环,这样是行不通的,因为我们不知道结束条件是什么;可能有人会想“让单个指针与带环链表的入口进行对比”,但是这有个问题,我们并不知道哪个节点是这个环形链表的节点。
类似下图
在这里插入图片描述

尾节点的next指向哪里是不确定的,有可能指向头节点,也有可能指向其他节点(极端情况指向自己),还有可能就不是一个环形链表(指向NULL)。

所以这里要使用快慢指针(这是一个很棒的解题思路),在这个题我们就让慢指针走一步,快指针走两步。
具体代码如下

struct ListNode* slow = head , *fast = head;
slow = slow->next;//慢指针走一步
fast = fast->next->next;//快指针走两步

这个指针不可能只会走一次的,所以是需要循环来完成的

bool hasCycle(struct ListNode *head) {struct ListNode* slow = head , *fast = head;while(){slow = slow->next;fast = fast->next->next;}return false;//链表不为环形链表}

这里的结束条件是什么呢?
这里是判断该链表是否为环形链表,所以我们的判断条件是fast != NULL && fast->next != NULL
这里为什么要判断fast->next呢,假设这条链表不是环形链表,且fast->next是指向NULL,如果我们不对 fast->next进行判断的话,进入循环就会出现fast->next已经为空,我们还对他进行了解引用,这样就会报错
所以这里的结束条件为

while(fast && fast->next)
{…………//代码段
}

好了,循环已经写好了,那么来写结束条件吧(判断是否带环),不能说因为代码死循环了就说链表是环形链表吧。
当slow等于fast时就表示该链表为环形链表。
为什么呢?
我们借图来了解:

开始将head赋予给slow和fast开始将head赋予给slow和fast
因为fast指针的行走速度是slow指针的两倍,所以当slow走了链表的中间节点时,fast就已经走到尾节点了。
在这里插入图片描述

slow走到尾节点时,就代表slow也进环了,这时候就成了追击问题,当fast == slow时,就代表该链表是环形链表。
完整代码如下:

bool hasCycle(struct ListNode *head) {struct ListNode* slow = head , *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow == fast)//相等,代表为环形链表{return true;}}return false;//不是环形链表
}

题目衍生问题

  1. 为什么一定为相遇,难道不会错过了,再也无法相遇呢?
  2. 如果我的fast走的不是两步,而是三步,四步或者更多呢?

衍生问题一

要证明这个很简单。
slow走到尾节点时,就代表slow也进环了,但这时候的fast的位置是不确定(可能已经转了好多圈了),所以我们假设fastslow的距离为N
如图:
在这里插入图片描述
因为fast是slow的两倍,所以追击一次,他俩之间的距离就会减一,一直追击下去距离就会一直减一,直到为0,也就是他两相等了

距离:N -> N-1 -> N-2 -> ……-> 2 -> 1 -> 0

因为fast是slow的两倍,所以每追击一次,他们的距离就会减一,所以他们两个不会错过。

衍生问题二

我们拿fast一次走三步来举例(其他的证明过程都大差不多,无非就是更复杂了)。
这时fast的速度就是slow的三倍,这时每追击一次,距离就会减二,这时候就要考虑两个情况了

  • 情况一:他们两个之间的距离为偶数
    这很简单,因为N为偶数,所以N%2=0;所以他们一定会在第一轮相遇。
  • 情况二:距离为奇数
    这样追击下去,当他们之间的距离为1时,在追击一次后,fast就会跑到slow的前面,开启新一轮的追击

N为奇数: N -> N-2 -> N-4 -> …… -> 5 -> 3 -> 1 -> -1

假设这个环形链表的长度为C。
这时候又要看两种情况这个C-1是否为偶数;
当C-1为偶数时,那么就和情况一一样,就一定会相遇。
如果C-1还是奇数,那就真的永远都遇不到了。

那么真的会出现N为奇数,C为偶数(C-1为奇)的情况吗?
其实是不可能的,我们将他们进行换算就可以知道为什么了。
在这里插入图片描述

总结论:使用快慢指针,环形链表一定会相遇,如果N为偶数,那么C一定为偶数;N为奇数,C一定为奇数。

题目二

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

这里就是在判断环形链表的基础上再加一些要求,那前置的代码,可以直接使用上面的代码

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow = head , *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow == fast)//相遇了{}}return NULL;//无环
}

那既让相遇了,我们肯定就是在相遇之后进行操作,也就是在if语句里写代码。
既让已经相遇了,那么slow的步数就为L+N(slow在环内走了 N 步),fast的步数就为L + x*C + N(走了一圈x就加1,然后因为slow在环内走了 N 步,使用就为x*C+N)。
我们将slowfast相遇时的节点,给到meet

        if(slow == fast)//相遇了{struct ListNode* meet = slow;//这里给fast也行}

我们看图来进行换算:
在这里插入图片描述
完整代码:

struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow = head , *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;if(slow == fast){struct ListNode* meet = slow;while(meet != head)//同时走{meet = meet->next;head = head->next;}return meet;//走到这里就代表meet == head}}return NULL;
}

其实这两题本意都不难,难的是衍生问题和背后的数学逻辑(其实拆开了也不难),所以这也成了以前面试时会考的点,
考察的是你的逻辑思维。

结语

最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言,也可以前往我的主页看更多好文哦(点击此处跳转到主页)。
如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!

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

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

相关文章

leetcode230 二叉搜索树中第K小的元素

题目 给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。 示例 输入:root [5,3,6,2,4,null,null,1], k 3 输出:3 解析 这道题应该是能做出…

【HMGD】STM32/GD32 I2C DMA 主从通信

STM32 I2C配置 主机配置 主机只要配置速度就行 从机配置 从机配置相同速度,可以设置第二地址 因为我的板子上面已经有了上拉电阻,所以可以直接通信 STM32 I2C DMA 定长主从通信代码示例 int state 0; static uint8_t I2C_recvBuf[10] {0}; stat…

扭矩拧紧螺栓简便的估算方法

扭矩拧紧螺栓简便的估算方法。 计算公式: T K x D x P 其中:T为拧紧力矩;D为螺纹公称直径;P为预紧力;K为拧紧系数。 预紧力计算公式:P(0.75~0.9) σsAs;其中前面系数对可拆连接取0.75&#xff0…

NLP(18)--大模型发展(2)

前言 仅记录学习过程,有问题欢迎讨论 Transformer结构: LLM的结构变化: Muti-head 共享: Q继续切割为muti-head,但是K,V少切,比如切为2个,然后复制到n个muti-head减少参数量,加速训练 atte…

运维开发.索引引擎ElasticSearch.倒序索引的概念

运维开发.索引引擎ElasticSearch 倒序索引的概念 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn…

两步将 CentOS 6.0 原地升级并迁移至 RHEL 7.9

《OpenShift / RHEL / DevSecOps 汇总目录》 说明 本文介绍如何将一个 CentOS 6.0 的系统升级并转换迁移到 RHEL 7.9。 本文是《在离线环境中将 CentOS 7.X 原地升级并迁移至 RHEL 7.9》阶进篇。 所有被测软件的验证操作可参见上述前文中对应章节的说明。 准备 CentOS 6.…

如何选择序列化协议:关键因素与场景分析

如何选择序列化协议:关键因素与场景分析 序列化协议的选择直接影响着系统的性能、可维护性及跨平台兼容性。以下是针对不同场景下,几种常见序列化协议的选择建议: 1. 公司间系统调用(性能要求宽松) SOAP (基于XML)&a…

1103 缘分数(测试点4)

solution 测试点4&#xff1a;1 1不符合缘分数定义&#xff0c;但是这个判断能够通过记得排除掉 #include<iostream> #include<cmath> using namespace std; bool judge(int n){int t sqrt(n);if(t * t n) return true;return false; } int main(){int n, m, c…

【大比武07】人工智能技术赋能城建档案高质量发展

关注我们 - 数字罗塞塔计划 - # 大比武2024 本篇是参加“华夏伟业”杯第二届档案信息化公司业务与技术实力大比武&#xff08;简称“大比武 2024”&#xff09;的投稿文章&#xff0c;来自讯飞知喻&#xff08;安徽&#xff09;科技有限公司&#xff0c;作者&#xff1a;张海剑…

《TortoiseSVN》简单使用说明

##################工作记录#################### 常用图标说明 一个新检出的工作副本 修改过的文件 更新过程遇到冲突的文件 你当前对文件进行了锁定&#xff0c;不要忘记不使用后要解锁&#xff0c;否则别人无法使用 当前文件夹下的某些文件或文件夹已经被调度从版本控制…

阿里架构师整理:100套Java经典实战项目+源码!拿走玩去,练不会我直接退出IT

技术学习的目的是进行项目开发&#xff0c;但是很多同学苦于自学没有项目练手&#xff0c;被面试官问到项目经验&#xff0c;项目就成了自己的短板。小编特地收集了阿里架构师整理的java实战项目来满足大家的需求&#xff0c;让大家在实战中不断成长&#xff01; 话不多说了&…

基于Pytorch框架的卷积神经网络MNIST手写数字识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 MNIST手写数字数据集是机器学习领域中的一个经典数据集&#xff0c;它包含了大量的手写数字图…

探索 JavaScript 新增声明命令与解构赋值的魅力:从 ES5 迈向 ES6

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;JavaScript 精粹 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; ES5、ES6介绍 文章目录 &#x1f4af;声明命令 let、const&#x1f35f;1 let声明符&a…

leetcode437 路径总和III-哈希表+前缀和

题目 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节…

618哪些好物值得入手?必备数码好物清单分享

618购物节又来了!一大波智能好物来袭!随着科技的日新月异&#xff0c;智能产品已成为我们生活中不可或缺的一部分&#xff0c;它们不仅炫酷&#xff0c;还能让你生活更便捷。想知道今年都有哪些黑科技新品吗?赶紧跟我们一起&#xff0c;我们将详细介绍这些热门好物。一堆超炫酷…

免费SSL证书与付费SSL证书:特性对比与适用场景解析

近几年随着互联网的发展&#xff0c;线上教育、线上办公&#xff0c;线上学习等逐渐融入我们的生活。与此同时&#xff0c;信息数据泄露等网络安全问题也日益突出&#xff0c;为了保护企业与用户的隐私信息&#xff0c;越来越多的公司选择安装SSL证书来保护网站和平台的数据安全…

poi操作word模板,对原有的word修改

/*** 化工园区调查表** param templatePath* param outPath* param parkInterview*/public static String getDocx(String templatePath, String outPath, ParkInterview parkInterview){File file new File(templatePath);File file1 new File(outPath);if(!file1.exists()…

计算机网络数据链路层知识点总结

3.1 数据链路层功能概述 &#xff08;1&#xff09;知识总览 &#xff08;2&#xff09;数据链路层的研究思想 &#xff08;3&#xff09;数据链路层基本概念 &#xff08;4&#xff09;数据链路层基本功能 3.1 封装成帧和透明传输 &#xff08;1&#xff09;数据链路层功能…

简单几步免费申请通配符/泛域名SSL证书

申请免费通配符SSL证书的过程可能会因不同的证书颁发机构(CA)而异&#xff0c;但以下是一般步骤&#xff0c;基于当前可获得的信息&#xff0c;特别是提及了JoySSL作为提供免费通配符证书的服务商之一。请注意&#xff0c;情况可能会随时间变化&#xff0c;因此建议直接访问相关…

文件传输服务应用1——java集成smb2/3详细教程和windows共享服务使用技巧

在实际项目开发过程中&#xff0c;读取网络资源或者局域网内主机的文件是必要的操作和需求。而FTP&#xff08;文件传输协议&#xff09;和SMB&#xff08;服务器消息块&#xff09;是两种最为常见的文件传输协议。它们各自在文件传输领域拥有独特的优势和特点&#xff0c;但同…