力扣刷题#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 == f 时 f->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仅负责文本修饰,综合获得以上内容。

浙公网安备 33010602011771号