【Hot 100 刷题计划】 LeetCode 142. 环形链表 II | C++ 哈希表直觉解法

LeetCode 142. 环形链表 II

📌 题目描述

题目级别:中等

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

不允许修改 链表。

  • 示例 1:
    输入:head = [3,2,0,-4], pos = 1
    输出:返回索引为 1 的链表节点
    解释:链表中有一个环,其尾部连接到第二个节点。

💡 解法一:哈希表备忘录

想要找到"环的入口",最直接的想法就是"留下脚印"。

我们在遍历链表的过程中,把路过的每一个节点的指针都记在哈希表(HashSet)里。

不断往前走,每走到一个新节点,都先去查一下表:

  1. 如果表中不存在,就把当前节点记录下来,继续往下走。
  2. 如果走到某个节点,发现它已经在哈希表里了 !那么毫无疑问,这个节点就是我们绕了一圈后第一次重新踏足的地方,它就是环的入口节点
  3. 如果一路走到 nullptr,说明这是一条直线,直接返回 null

💻 C++ 代码实现 (哈希表法)

cpp 复制代码
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 使用 unordered_set 记录已经访问过的节点
        unordered_set<ListNode*> seen;
        
        while (head != nullptr)
        {
            // 如果当前节点已经被访问过,它就是环的入口
            if (seen.count(head)) return head;
            
            // 记录当前节点
            seen.insert(head);
            // 向后移动
            head = head->next;
        }

        // 走到了链表尽头,无环
        return nullptr;
    }
};

💡 解法二:Floyd 判环算法 (龟兔赛跑进阶)

这道题是考察数学推导的经典之作。我们可以用快慢指针分两阶段解决:

阶段 1:判断是否有环,并找到相遇点

定义快指针 fast (每次 2 步) 和慢指针 slow (每次 1 步)。如果它们在某处相遇了,说明一定有环。

阶段 2:寻找环的入口 (数学推导)

设起点到入口的距离为 xxx。

设入口到相遇点的距离为 yyy。

设相遇点到入口的剩余距离为 zzz。

  • slow 走了 x+yx + yx+y
  • fast 走了 x+y+n(y+z)x + y + n(y + z)x+y+n(y+z)
    因为 fast 的速度是 slow 的两倍:
    2(x+y)=x+y+n(y+z)2(x + y) = x + y + n(y + z)2(x+y)=x+y+n(y+z)
    化简得到:
    x=(n−1)(y+z)+zx = (n - 1)(y + z) + zx=(n−1)(y+z)+z
    这个极其漂亮的公式告诉我们:起点到环入口的距离 xxx,刚好等于相遇点走到环入口的距离 zzz(再加上几圈闲逛)。

行动指南:

当两指针相遇后,我们把其中一个指针扔回起点 ,另一个留在相遇点。然后两人速度保持一致(都每次走 1 步)。当他们再次相遇时,相交的节点必定是环的入口!


💻 C++ 代码实现 (快慢指针最优解)

cpp 复制代码
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (!head || !head->next) return nullptr;

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

        // 阶段 1:快慢指针寻找相遇点
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;

            // 如果相遇了,进入阶段 2
            if (slow == fast) {
                // 将其中一个指针重置到头部
                ListNode *p1 = head;
                ListNode *p2 = slow;

                // 两人以相同速度前进,相遇点即为环入口
                while (p1 != p2) {
                    p1 = p1->next;
                    p2 = p2->next;
                }
                
                return p1;
            }
        }

        return nullptr;
    }
};
相关推荐
嘻嘻哈哈樱桃2 小时前
牛客经典101题题解集--哈希
java·数据结构·python·算法·leetcode·职场和发展·哈希算法
fish_xk2 小时前
c++中的继承
开发语言·c++
Brilliantwxx2 小时前
【算法题】日期类算法题
开发语言·c++·笔记·程序人生·算法
穿条秋裤到处跑2 小时前
每日一道leetcode(2026.04.27):检查网格中是否存在有效路径
算法·leetcode·职场和发展
想唱rap2 小时前
TCP套接字编程
java·linux·网络·c++·tcp/ip·mysql·ubuntu
我不是懒洋洋2 小时前
【数据结构】二叉树链式结构的实现(二叉树的遍历、使用二叉树的基本方法、二叉树的创建和销毁)
c语言·数据结构·c++·经验分享·算法·链表·visual studio
水木流年追梦2 小时前
CodeTop Top 300 热门题目8-字符串解码
linux·运维·服务器·前端·算法·leetcode
玖別ԅ(¯﹃¯ԅ)2 小时前
C++ Qt + OpenCV 实现本地人脸识别系统:摄像头采集、ONNX模型加载、人脸库比对完整流程
c++·qt
lcj25112 小时前
精选5大高频链表与数组算法详解:从旋转数组到链表公共节点,LeetCode实战代码+图解全解析
算法·leetcode·链表