⭕一文解决环形链表问题 没写完

链表

链表是一种常见的数据结构,用于存储线性序列。与数组不同,链表中的元素在内存中不是连续存储的,而是通过指针相连。链表由一个头指针指向链表的第一个节点,每个节点包含两个部分:数据域和指针域。数据域存储节点的数据,指针域指向下一个节点的地址。

链表有多种类型

  • 单向链表中每个节点只有一个指针域,指向下一个节点;
  • 双向链表中每个节点有两个指针域,一个指向前一个节点,一个指向后一个节点;
  • 环形链表中最后一个节点的指针域指向头节点,形成一个环。

环形链表

环形链表问题是一类非常经典的链表问题,给定一个单向链表,判断这个链表是否存在环或者环的状态。

这类问题通常有两种解法。

  • 快慢指针法:使用两个指针,一个快指针和一个慢指针,快指针每次移动两个节点,慢指针每次移动一个节点,如果链表中存在环,则快指针最终会追上慢指针,否则快指针会到达链表末尾结束。这个算法的时间复杂度是 O(n),其中 n 是链表的长度。

  • 哈希表法:遍历链表中的每个节点,每访问一个节点就将它存储到哈希表中,如果访问到了哈希表中已经存在的节点,说明链表中存在环。这个算法的时间复杂度也是 O(n),其中 n 是链表的长度,但需要额外的空间来存储哈希表。

快慢指针法其实就是 Floyd 判圈算法,接下来我们详细介绍一下:

Floyd判圈算法

Floyd判圈算法(又称龟兔赛跑算法)是一种快速检测链表中是否存在环的算法。该算法使用两个指针,一个慢指针和一个快指针,从链表头部开始同时向后遍历链表,每次快指针比慢指针多走一步,直到快指针走到链表末尾或者两个指针相遇。

如果链表中不存在环,那么快指针最终会走到链表的末尾,算法结束。如果链表中存在环,那么快指针最终会在环内与慢指针相遇,算法会返回存在环的结论。

该算法的时间复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n),其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 是链表的长度。由于该算法使用的是常数级别的额外空间,因此它是一种空间复杂度比较优秀的算法。

Floyd 判圈算法的正确性可以通过数学归纳法来证明。

假设链表中存在环,且环的长度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k。设慢指针走了 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x 步后进入环,快指针走了 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 x 2x </math>2x 步后进入环。设快指针比慢指针多走了 <math xmlns="http://www.w3.org/1998/Math/MathML"> y y </math>y 圈( <math xmlns="http://www.w3.org/1998/Math/MathML"> y ≥ 1 y\geq 1 </math>y≥1),则有:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> 2 x = x + k y + z 2x=x+ky+z </math>2x=x+ky+z

其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> z z </math>z 表示慢指针在环内走的步数。因为快指针的速度是慢指针的两倍,所以可以得到:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> z = k − x % k z=k − x \% k </math>z=k−x%k

也就是说,慢指针在环内走了 <math xmlns="http://www.w3.org/1998/Math/MathML"> k − x % k k - x \% k </math>k−x%k 步。由于 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ≤ x % k < k 0\leq x \% k < k </math>0≤x%k<k,因此 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 ≤ k − x % k < k 0\leq k - x \% k < k </math>0≤k−x%k<k,所以 <math xmlns="http://www.w3.org/1998/Math/MathML"> z > 0 z > 0 </math>z>0 且 <math xmlns="http://www.w3.org/1998/Math/MathML"> z < k z < k </math>z<k。

因为快指针每次走两步,所以 <math xmlns="http://www.w3.org/1998/Math/MathML"> z z </math>z 的取值只有 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 种可能。当 <math xmlns="http://www.w3.org/1998/Math/MathML"> z = 0 z=0 </math>z=0 时,表示快指针与慢指针相遇,此时算法会返回存在环的结论;当 <math xmlns="http://www.w3.org/1998/Math/MathML"> z ≠ 0 z\neq 0 </math>z=0 时,表示快指针和慢指针在环内继续前进,由于快指针比慢指针多走了一圈,因此可以将 <math xmlns="http://www.w3.org/1998/Math/MathML"> x x </math>x 的值更新为 <math xmlns="http://www.w3.org/1998/Math/MathML"> k − z k - z </math>k−z,这样快指针和慢指针都在环内距离环入口的距离为 <math xmlns="http://www.w3.org/1998/Math/MathML"> k − z k - z </math>k−z,再次相遇的位置就是环的入口。

由此可见,Floyd 判圈算法的正确性是得到了保证的。

相关推荐
好开心啊没烦恼几秒前
Python 数据分析:计算,分组统计1,df.groupby()。听故事学知识点怎么这么容易?
开发语言·python·数据挖掘·数据分析·pandas
lljss20201 小时前
Python11中创建虚拟环境、安装 TensorFlow
开发语言·python·tensorflow
课堂剪切板1 小时前
ch03 部分题目思路
算法
空中湖1 小时前
tensorflow武林志第二卷第九章:玄功九转
人工智能·python·tensorflow
山登绝顶我为峰 3(^v^)32 小时前
如何录制带备注的演示文稿(LaTex Beamer + Pympress)
c++·线性代数·算法·计算机·密码学·音视频·latex
CodeCraft Studio2 小时前
CAD文件处理控件Aspose.CAD教程:使用 Python 将绘图转换为 Photoshop
python·photoshop·cad·aspose·aspose.cad
Two_brushes.3 小时前
【算法】宽度优先遍历BFS
算法·leetcode·哈希算法·宽度优先
Python×CATIA工业智造4 小时前
Frida RPC高级应用:动态模拟执行Android so文件实战指南
开发语言·python·pycharm
onceco4 小时前
领域LLM九讲——第5讲 为什么选择OpenManus而不是QwenAgent(附LLM免费api邀请码)
人工智能·python·深度学习·语言模型·自然语言处理·自动化
森焱森5 小时前
水下航行器外形分类详解
c语言·单片机·算法·架构·无人机