跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

LeetCode 142:链表环的起点检测

介绍使用快慢指针算法解决 LeetCode 142 环形链表 II 问题。通过数学推导证明,当快慢指针在环内相遇后,将其中一个指针重置至链表头,两者以相同速度前进,再次相遇点即为环入口。该方法时间复杂度 O(n),空间复杂度 O(1),是解决此类问题的最优解之一。文章包含 C++ 代码实现、细节解析及常见调试技巧。

雪落无声发布于 2026/3/30更新于 2026/5/2426 浏览
LeetCode 142:链表环的起点检测

🌟 引言

链表环检测问题在 C++ 中同样是一个经典面试题。本文将用 C++ 实现 LeetCode 142 题'环形链表 II'的解决方案,深入讲解快慢指针算法的原理和实现细节。

🔍 问题描述

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

🧠 解题思路回顾

快慢指针算法

  1. 使用两个指针:slow每次走一步,fast每次走两步
  2. 如果两指针相遇,说明链表有环
  3. 将其中一个指针重置到链表头,然后两指针以相同速度前进
  4. 再次相遇的位置就是环的起点

数学原理

设:

  • 链表头到环起点距离:a
  • 环起点到相遇点距离:b
  • 相遇点到环起点距离:c

则有:

  • 第一次相遇时:slow走了a+b,fast走了a+b+c+b
  • 因为fast速度是slow的两倍:2(a+b) = a+2b+c
  • 推导得:a = c

💻 C++代码实现

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 边界条件处理
        if (head == nullptr || head->next == nullptr) {
            return nullptr;
        }
        ListNode *slow = head;
        ListNode *fast = head;
        // 第一阶段:检测是否有环
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) {
                break; // 相遇说明有环
            }
        }
        // 检查是否因为无环退出循环
        if (fast == nullptr || fast->next == nullptr) {
            return nullptr;
        }
        // 第二阶段:寻找环起点
        slow = head; // 重置慢指针到头部
        while (slow != fast) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow; // 相遇点即为环起点
    }
};

🛠 代码解析

数据结构定义

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

这是 LeetCode 标准的链表节点定义,包含一个整数值和指向下一个节点的指针。

算法实现细节

寻找环起点:

slow = head; // 重置慢指针到头部
while (slow != fast) {
    slow = slow->next;
    fast = fast->next;
}

根据数学推导,两指针以相同速度前进,再次相遇点即为环起点。

无环检查:

if (fast == nullptr || fast->next == nullptr) {
    return nullptr;
}

如果因为快指针无法前进而退出循环,说明无环。

环检测阶段:

while (fast != nullptr && fast->next != nullptr) {
    slow = slow->next;
    fast = fast->next->next;
    if (slow == fast) {
        break; // 相遇说明有环
    }
}

快指针每次走两步,慢指针每次走一步,直到相遇或快指针无法前进。

指针初始化:

ListNode *slow = head;
ListNode *fast = head;

快慢指针都从头节点开始。

边界条件处理:

if (head == nullptr || head->next == nullptr) {
    return nullptr;
}

处理空链表或单节点链表的特殊情况。

🚀 性能分析

  • 时间复杂度:O(n)
    • 最坏情况下需要遍历链表两次
  • 空间复杂度:O(1)
    • 只使用了固定数量的指针变量

🐞 常见问题与调试

常见错误

  1. 初始条件处理: 忘记处理空链表或单节点链表的情况。
  2. 指针重置错误: 在第二阶段错误地重置了快指针而不是慢指针。

空指针访问:

while (fast != nullptr && fast->next != nullptr)

必须同时检查 fast 和 fast->next,否则可能访问空指针的 next 成员。

调试技巧

  1. 小规模测试:
    • 无环链表:1->2->3->null
    • 有环链表:1->2->3->4->2(环在节点 2)
  2. 边界测试:
    • 空链表
    • 单节点自环链表
    • 双节点互相指向的链表

打印指针地址:

cout << "Slow: " << slow << " Fast: " << fast << endl;

帮助跟踪指针移动情况。

📊 复杂度对比表

方法时间复杂度空间复杂度适用场景
哈希表法O(n)O(n)需要简单实现时
快慢指针O(n)O(1)需要节省空间时

🌈 总结

通过 C++ 实现的快慢指针算法,我们能够高效地解决链表环检测问题。关键在于:

  1. 理解快慢指针相遇的数学原理
  2. 正确处理边界条件和指针访问

分两个阶段实现:环检测和环起点定位

这种方法不仅高效(O(n) 时间,O(1) 空间),而且体现了算法设计的巧妙之处。掌握这个技巧,你就能轻松应对链表相关的各种环检测问题了!

目录

  1. 🌟 引言
  2. 🔍 问题描述
  3. 🧠 解题思路回顾
  4. 快慢指针算法
  5. 数学原理
  6. 💻 C++代码实现
  7. 🛠 代码解析
  8. 数据结构定义
  9. 算法实现细节
  10. 🚀 性能分析
  11. 🐞 常见问题与调试
  12. 常见错误
  13. 调试技巧
  14. 📊 复杂度对比表
  15. 🌈 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Python 环境搭建指南:二级 Python 考试配置
  • OpenClaw 本地 AI 智能体 Windows10 一键部署指南
  • 工作四年被辞退:程序员的职业反思与学习复盘
  • Claude Skills 详解:功能特性与实战应用
  • MySQL 内置函数指南:日期、字符串与数学函数实战
  • WebGIS 开发:WKT 转 GeoJSON 技巧与 Leaflet 加载应用
  • 树莓派 5 部署冬瓜 HAOS:智能家居中枢搭建指南
  • OpenClaw Windows 10 本地 AI 智能体一键部署指南
  • Spring Boot 日志体系与实战指南
  • 关闭VSCode的GitHub Copilot功能
  • faster-whisper 快速安装与使用指南
  • VS Code 结合 Overleaf 实现本地 AI 辅助写作
  • 相交链表 - 双指针解法
  • 通过官方 API 搭建 QQ 群聊机器人
  • RISC-V开源处理器实战:从Verilog RTL设计到FPGA原型验证
  • VS Code 配置 Claude Code 时 Git Bash 路径报错解决
  • Gazebo 机器人三维物理仿真平台详解
  • C语言Web开发:CGI、FastCGI与Nginx技术详解
  • C++ 模板编程详解:从函数模板到类模板
  • macOS 双开与多开微信 WeChat 教程(支持 4.X 及以上版本)

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online