【算法--链表】141.环形链表(通俗讲解链表中是否有环)
一、题目是啥?一句话说清
给你一个链表,判断这个链表中是否存在环(即链表的某个节点可以通过next指针再次到达)。
二、解题核心
使用快慢指针法:让两个指针以不同速度遍历链表,如果存在环,快指针最终会追上慢指针;如果不存在环,快指针会先到达链表末尾。
这就像两个人在环形跑道上跑步,一个跑得快,一个跑得慢。如果跑道是环形的,快的人最终会追上慢的人;如果是直线跑道,快的人会先到达终点。
三、关键在哪里?(3个核心点)
想理解并解决这道题,必须抓住以下三个关键点:
1. 快慢指针的选择
- 是什么:使用两个指针,慢指针每次移动一步,快指针每次移动两步。
- 为什么重要:这种速度差确保了如果存在环,快指针一定会追上慢指针(就像在环形跑道上,速度快的人一定会追上速度慢的人)。
2. 循环终止条件
- 是什么:循环继续的条件是快指针和快指针的下一个节点都不为空。
- 为什么重要:这样可以确保在移动快指针时不会出现空指针异常,同时当快指针到达链表末尾时,可以确定没有环。
3. 相遇判断
- 是什么:在每次移动后,检查快慢指针是否指向同一个节点。
- 为什么重要:如果快慢指针相遇,说明存在环;如果快指针到达链表末尾,说明没有环。
四、看图理解流程(通俗理解版本)
让我们用几个例子来可视化过程:
示例1:有环的情况
链表:1 → 2 → 3 → 4 → 2(形成环,4指向2)
-
初始化:
- 慢指针指向1,快指针指向1
- 状态:慢@1, 快@1
-
第一轮移动:
- 慢指针移动一步到2
- 快指针移动两步到3
- 状态:慢@2, 快@3
-
第二轮移动:
- 慢指针移动一步到3
- 快指针移动两步到2(从3移动两步:3→4→2)
- 状态:慢@3, 快@2
-
第三轮移动:
- 慢指针移动一步到4
- 快指针移动两步到4(从2移动两步:2→3→4)
- 状态:慢@4, 快@4
-
相遇:快慢指针都指向4,说明有环,返回true
示例2:无环的情况
链表:1 → 2 → 3 → 4 → null
-
初始化:
- 慢指针指向1,快指针指向1
- 状态:慢@1, 快@1
-
第一轮移动:
- 慢指针移动一步到2
- 快指针移动两步到3
- 状态:慢@2, 快@3
-
第二轮移动:
- 慢指针移动一步到3
- 快指针移动两步到null(从3移动两步:3→4→null)
- 状态:慢@3, 快@null
-
结束:快指针为null,说明没有环,返回false
五、C++ 代码实现(附详细注释)
#include <iostream>
using namespace std;// 链表节点定义
struct ListNode {int val;ListNode *next;ListNode