当前位置: 首页 > news >正文

C++代码随想录刷题知识分享-----142.环形链表II

1. 题目要求

给定一个链表的头节点  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) 空间解决此题

    2. 算法思想 —— 快慢指针 Floyd 判环算法

    🧠 思路拆解:

    1. 第一阶段:判断是否有环

      • 设置两个指针:slow 每次走一步,fast 每次走两步。
      • fast 在某一时刻追上 slowslow == fast),说明链表有环。
      • 否则,fastfast->next 先到 nullptr,说明无环。
    2. 第二阶段:寻找环的入口节点

      • 新建一个指针 cur 从链表头开始。
      • curslow 每次都走一步,最终会在环的起点相遇。

    3. 完整注释版代码

    class Solution {
    public:ListNode *detectCycle(ListNode *head) {ListNode* slow = head;ListNode* fast = head;// 第一阶段:先判断链表是否有环(快慢指针)while (fast != nullptr && fast->next != nullptr) {slow = slow->next;           // 慢指针走一步fast = fast->next->next;     // 快指针走两步if (slow == fast) {          // 有环,找到相遇点// 第二阶段:从 head 和相遇点出发,再次相遇即为入环点ListNode* cur = head;while (cur != slow) {cur = cur->next;slow = slow->next;}return cur;              // 入环起点}}return nullptr; // fast 跑到了 null,无环}
    };
    

    4. 为什么相遇点到入环点距离 = 头到入环点距离?

    4.1. 变量定义(统一符号)

    • L:head 到入环点的距离(非环部分长度)
    • C:环的总长度(环的周长)
    • x:入环点到相遇点的距离(顺时针方向)
    • k:快指针比慢指针多绕的圈数
    • m:慢指针从入环点走到相遇点时走的距离,即 x
    • D:从相遇点再走 C - x 就是回到入环点的距离

    4.2. 数学推导(核心逻辑)

    设快慢指针在某个时刻第一次相遇:

    • 慢指针走了:L + x
    • 快指针走了:L + x + k * C(因为比慢指针多走 k 圈环)

    因为快指针每次走 2 步,慢指针走 1 步,所以:

    2(L + x) = L + x + kC
    

    化简得:

    L + x = kC   →   L = kC - x
    

    🔥 结论来了:

    相遇点再走 C - x会到入环点
    head 走 L = kC - x也会到入环点

    所以:

    一个指针从 head 出发,一个从相遇点出发,每次走一步,它们会在入环点相遇。


    🔁 3. 图形辅助理解

    链表结构如下( 表示 next):

    head → ... → (入环点) → a → b → c → ... → x↑            ↓←←←←←←←←←←←←←←
    

    设相遇发生在环中的节点 x,从入环点到 x 走了 x 步。
    你从 head 出发到达入环点,也走了 kC - x 步。

    • 慢指针再走 C - x 就回到入环点;
    • 而从 head 出发刚好也走了 kC - x 步;
    • 两者同时走,都会在入环点碰面。

    🧪 4. 举个例子

    假设链表如下:

    head → A → B → C → D → E → → → →↑       ↓H ← G ← F
    
    • 入环点是:E
    • 环:E → F → G → H → E(长度 C = 4
    • 假设快慢指针第一次相遇在 G,即入环点 E 到相遇点 G 的距离是 x = 2
    • 则:
      • L = kC - x = 1×4 - 2 = 2
      • 也就是说,从 head 到 E 有两步
      • G 再走 C - x = 2 步也回到 E
    • 两者同时走,都会在 E 相遇 

    根据 Floyd 判环算法推导,在第一次相遇后,从头节点和相遇点各起一指针,每次一步,它们将同时在入环点相遇

    原因是:
    相遇前慢指针走了 L + x,快指针走了 L + x + kC,由快慢速比得出:
    2(L + x) = L + x + kC → L = kC - x,即从 head 到入环点的距离等于从相遇点到入环点的距离。
    所以两个指针每次走一步,最终会同步到达入环点。


    5. 时间与空间复杂度

    指标复杂度
    时间复杂度O(n) 最多遍历两次链表
    空间复杂度O(1) 不使用额外数据结构

    6. 扩展面试题 & 必会变体

    问题解法提示
    如何判断链表是否有环?Floyd 判环算法
    如何找出环的起始点?相遇后双指针同步走
    环的长度是多少?相遇后在环中走一圈计数
    如果链表有交点 + 有环怎么办?必须分环内交点、环前交点、多环链表等情况分析

    7. 小结

    知识点一句话记忆
    Floyd 判环快慢指针相遇即有环
    入环点求法相遇后设新指针从 head 出发,与 slow 同步走
    空间优化不使用哈希表,仅用指针操作
    不允许修改链表结构所以不能破坏 next 指针或用标记法
    http://www.xdnf.cn/news/266383.html

    相关文章:

  • 希洛激活器策略思路
  • n8n工作流自动化平台的实操:Cannot find module ‘iconv-lite‘
  • 生成式 AI 与 AI 的区别
  • DeepSeek实战--LLM微调
  • LeetCode算法题 (设计链表)Day16!!!C/C++
  • 「Mac畅玩AIGC与多模态16」开发篇12 - 多节点串联与输出合并的工作流示例
  • ipvsadm,是一个什么工具?
  • 中国 AIGC 确权革命:“AI 创意・中国” 平台上线,存证成本降至 0.1 元 / 件
  • CAN网桥中继隔离抗干扰集线器重映射一进一出CAN扩展CAN Bridge
  • 在Java项目中实现本地语音识别与热点检测,并集成阿里云智能语音服务
  • Dubbo(92)如何在微服务架构中应用Dubbo?
  • 深入理解C++类型转换:从基础到高级应用
  • 糖尿病筛查常识---秋浦四郎
  • 计网_可靠传输ARQ机制
  • neo4j初尝试
  • Java从入门到精通 - Java语法
  • C++ 简单工厂模式详解
  • QT6 源(72):阅读与注释单选框这个类型的按钮 QRadioButton,及各种属性验证,
  • 【Linux知识】find命令行使用详解
  • 数据结构*队列
  • nessus最新版本安装教程+windows一键更新最新插件
  • 计算机网络-同等学力计算机综合真题及答案
  • 【AI零件】openrouter.ai生成密钥的操作
  • 广义线性模型三剑客:线性回归、逻辑回归与Softmax分类的统一视角
  • JavaScript 星河:类型流转的诗意旅程
  • 基于LangChain 实现 Advanced RAG-后检索优化(上)-Reranker
  • 第4章 Python 3 基础语法规则补充
  • LangChain与MCP:大模型时代的工具生态之争与协同未来
  • STM32F103C8T6使用MLX90614模块
  • VTK实战笔记(1)在win11搭建VTK-9.4.2 + qt5.15.2 + VS2019_x64开发环境