Floyd判圈算法(Floyd Cycle Detection Algorithm)

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨

👀👀👀 个人博客:小奥的博客

👍👍👍:个人CSDN

⭐️⭐️⭐️:Github传送门

🍹 本人24应届生一枚,技术和水平有限,如果文章中有不正确的内容,欢迎多多指正!

📜 欢迎点赞收藏关注哟! ❤️

文章目录

一、基础概念

Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一种用于检测有限状态机、迭代函数或链表结构中是否存在环路的算法。该算法不仅能判断环的存在性,还可确定环的起点位置及其长度。

算法采用双指针策略,通过不同移动速度的指针遍历数据结构,根据指针相遇情况判定环路特征。

  • 时间复杂度 O(n)
  • 空间复杂度 O(1)

初始化:

  • 快慢指针:fast = slow = head
  • 单列表节点定义:
python 复制代码
from typing import Optional

class Node:
    """单链表节点定义"""
    __slots__ = ("val", "next")
    def __init__(self, val: int, nxt: "Optional[Node]" = None):
        self.val = val
        self.next = nxt

二、检测是否有环

  1. 慢指针每次前进一步:slow = slow.next
  2. 快指针每次前进两步:fast = fast.next.next
  3. 快慢指针相遇(slow == fast),则链表中必含环;否则无环。

为什么有环快慢指针一定能相遇?

若存在环,快指针相对于慢指针速度为1步/轮,必然会在环内相遇。

python 复制代码
# -------------------------------------------------
# 1. 探测是否有环(返回相遇节点或 None)
# -------------------------------------------------
def detect_cycle(head: Optional[Node]) -> Optional[Node]:
    """Floyd 第一阶段:龟兔赛跑"""
    slow = fast = head
    while fast and fast.next:
        slow = slow.next          # 1 步
        fast = fast.next.next     # 2 步
        if slow is fast:          # 指针同一对象
            return slow           # 返回相遇点
    return None                   # 无环

三、查找环的入口

  1. 相遇后,让慢指针slow回到头结点,另一指针fast停在相遇点:slow=head
  2. 之后让慢指针slow继续走,并从头结点开始记录距离:slow=slow.next, head=head.next
  3. 两个结点再次相遇的节点为环的入口
python 复制代码
# -------------------------------------------------
# 2. 定位环入口(若无环返回 None)
# -------------------------------------------------
def find_cycle_entry(head: Optional[Node]) -> Optional[Node]:
    meet = detect_cycle(head)
    if meet is None:
        return None
    # 第二阶段:同步一步一步走
    slow = head
    while slow is not meet:
        slow = slow.next
        meet = meet.next
    return slow      # 或 meet,二者同一节点

四、求环的长度

方法 1:单指针绕环一周(最常用)

  1. 任选环内一个节点,记为 p(可用入口节点,也可用第一次相遇点)。
  2. 令 q = p.next,计数器 cnt = 1。
  3. 当 q ≠ p 时循环
    q = q.next;cnt++。
  4. 返回 cnt。
    结论 :cnt 就是环长度 L。
    时间 O(L),空间 O(1)。
    ------ 这就是最简洁的"公式"L = 单次遍历回到起点的步数

方法 2:双指针再跑一次"龟兔"------一次就同时求出 L 与验证

(如果忘记保存入口节点,或者想再练一次快慢指针,可以用这个变种)

  1. 在第一次相遇点后,保持慢指针不动,把快指针重新指向相遇点。
  2. 快指针每次走 1 步,计数器 cnt = 0。
  3. 循环直到两指针再次相遇:
    fast = fast.next;cnt++。
  4. 返回 cnt。
    结论 :cnt 就是 L。
    原理:相对速度为 0,快指针恰好多跑一整圈。
python 复制代码
# -------------------------------------------------
# 3. 计算环长度(若无环返回 0)
# -------------------------------------------------
def cycle_length(head: Optional[Node]) -> int:
    meet = detect_cycle(head)
    if meet is None:
        return 0

    # 方法 1:单指针绕环一周
    # cur, cnt = meet.next, 1
    # while cur is not meet:
    #     cur = cur.next
    #     cnt += 1
    # return cnt

    # 方法 2:把 fast 重新指向 meet,两者都一次一步
    slow = meet
    fast = meet.next        # 相对距离 1
    cnt = 1                 # 已经隔开 1 步
    while slow is not fast:
        fast = fast.next    # 每次一步
        cnt += 1
    return cnt
相关推荐
变量未定义~35 分钟前
最小生成树1(Prim模板)、最小生成树2(kruskal模板)、最近公共祖先(模板)
算法
这就是佬们吗38 分钟前
Python入门⑤-异常处理、文件操作与实战项目
开发语言·数据库·python·算法·pycharm
LONGZETECH1 小时前
新能源汽车充电设备装配与调试仿真教学软件 技术架构与核心实现解析
大数据·算法·3d·unity·架构·汽车
自学小白菜1 小时前
关于提升机器学习算法做预测回归任务精度的方法分享
算法·机器学习·回归·提升精度
学废了wuwu1 小时前
从入门到实战:深入浅出模型压缩三大核心——剪枝、彩票假设与知识蒸馏
人工智能·算法·剪枝
小肝一下1 小时前
3. 单链表
c语言·数据结构·c++·算法·leetcode·链表·dijkstra
劈星斩月1 小时前
监督学习算法 之 决策树
学习·算法·决策树
学计算机的计算基1 小时前
操作系统内存管理全解:虚拟内存、页表、COW、malloc、OOM一篇搞定
java·笔记·算法
tachibana21 小时前
hot100 前 K 个高频元素(347)
java·数据结构·算法·leetcode
To_OC9 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode