力扣刷题#17-0141-环形链表

力扣刷题#17-0141-环形链表

题目

给你一个链表的头节点 head,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。如果链表中存在环,则返回 true。否则,返回 false

输入:head = [3, 2, 0, -4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

我的第一版思路:计次法

看到这道题,我的第一反应是:走一定的步数,如果还没到尽头就说明有环

题目所给节点数不超过 1e4,所以我设了个计数上限。

class Solution {
public:
    bool hasCycle(ListNode *head) {
        const int M = 1e4 + 10;
        int cnt = 0;
        if (head == nullptr) return false;
        while (head != nullptr) {
            head = head->next;
            cnt++;
            if (cnt > M) return true;
        }
        return false;
    }
};

优化方向

这个解法的问题在于 M 是猜的。如果力扣换了个更大的测试用例,1e4+10 就可能不够用。


第二版:快慢指针(我的提交版本)

受"操场上跑步"的启发——快的人一圈后总会追上慢的人。我写了快慢指针版。

class Solution {
public:
    bool hasCycle(ListNode* head) {
        if (head == nullptr)
            return false;

        ListNode* s = nullptr, *f = nullptr;
        s = head;
        f = head;
        do {
            if (s->next != nullptr)
                s = s->next;
            else
                return false;

            if (f->next != nullptr && f->next->next != nullptr)
                f = f->next->next;
            else
                return false;
        } while (s != f && f->next != s);
        return true;
    }
};

AC 了,跑了 9ms。

踩坑记录

坑 :while 循环永远退不出来

while (s != f || f->next != s)   // ❌ 多了一个条件

s == ff->next != s 通常仍然为 true——第二个条件阻断了退出。

冗余条件分析

f->next != s 是多余的。快指针每次走两步、慢指针每次走一步,快指针不可能跳过慢指针——每轮间距缩小 1,要么正好追上,要么彻底走完。永远不会有"快指针在慢指针身后一步"但不等于的情况。

while (s != f)               // 够用了
while (s != f && f->next != s) // 多余

最终优化版(更简洁的标准写法)

class Solution {
public:
    bool hasCycle(ListNode* head) {
        ListNode *slow = head, *fast = head;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) return true;
        }
        return false;
    }
};
对比 我的提交版本 最终优化版
条件 两处 if-else 判空 一个 while 条件搞定
退出方式 先 return false,循环结束 return true 追上就 return true,走完就是 false
行数 17 7
可读性 一般
判定 9ms AC 相同复杂度

两者都是 O(n) 时间、O(1) 空间,最终优化版主要是代码更干净。


快慢指针的核心理解

生活化类比:

两个人同时绕操场跑——一个人跑得快(一次两步),一个人跑得慢(一次一步)。如果跑道是直的(无环),快的人会直接跑到终点。如果跑道是圈的(有环),快的人迟早会从后面追上慢的人。

条件 含义
fast 快指针,一次走两步
slow 慢指针,一次走一步
fast && fast->next 快指针还能安全往前走两步
slow == fast 追上了 → 有环

链表中的"相等"指的是指针值相等(指向同一个内存地址),不是 val 相等。 因为链表中可能有节点值相同但内存地址不同,不能用值去判断是否相遇。


复杂度分析

维度 说明
时间复杂度 O(n) 每个节点最多访问常数次
空间复杂度 O(1) 只用了两个指针

本文档由 AI 辅助生成,作者提供问题,思路和代码,AI仅负责文本修饰,综合获得以上内容。

posted @ 2026-06-17 15:23  STA_running  阅读(5)  评论(0)    收藏  举报