LeetCode Hot 100 —— 141.环形链表
141.环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:

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

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

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
方法一:遍历法(不推荐,反面教材)
遇事不决就开始遍历,肉眼可见的是一个笨方法,不过也可以通过。
bool hasCycle(struct ListNode *head) {
if(head == NULL || head->next == NULL) return 0;
struct ListNode *temp = head;
struct ListNode *pos_head = (struct ListNode*)malloc(sizeof(struct ListNode));
pos_head->next = NULL; // 初始为空,不预先塞入 head
struct ListNode *pos; // 只声明,不赋值
while(temp != NULL)
{
// 先检查当前 temp 是否已经在记录表中
pos = pos_head->next;
while(pos != NULL)
{
if((int)temp == pos->val) return 1;
pos = pos->next;
}
// 检查通过后,将当前 temp 的地址存入记录表
pos = (struct ListNode*)malloc(sizeof(struct ListNode)); // 直接复用 pos
pos->val = (int)temp;
pos->next = pos_head->next;
pos_head->next = pos;
// 移动到下一个原始节点
temp = temp->next;
}
return 0;
}
思路分析:
遍历链表,每访问一个节点,就将该节点的地址记录下来。之后每次访问新节点前,先检查该地址是否已存在于记录中,若存在则说明有环。
注意事项:
-
(int)temp将指针强制转换为int类型,在 64 位系统上会导致指针地址截断(int为 32 位,指针为 64 位),可能产生误判。建议使用uintptr_t来完整保存地址。 -
额外开辟的记录节点未被释放,存在内存泄漏。
-
时间复杂度 O(n²),空间复杂度 O(n),效率较低。
该方法仅作概念演示,实际工程中不推荐使用。
方法二:快慢指针(Floyd 判圈算法)
bool hasCycle(struct ListNode* head) {
if (head == NULL || head->next == NULL) {
return false;
}
struct ListNode* slow = head;
struct ListNode* fast = head->next;
while (slow != fast) {
if (fast == NULL || fast->next == NULL) {
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;
}
思路分析:
Floyd 判圈算法(快慢指针)的核心思想是:使用两个指针 slow 和 fast 同时遍历链表,slow 每次走一步,fast 每次走两步。如果链表中存在环,则 fast 最终一定会追上 slow(二者相遇);如果无环,则 fast 会先到达链表末尾(NULL)。
因为对于快指针来说,最终相遇的时候一定是走过了slow两倍的距离,也就是如果有环一定会相遇。
过程简述:
- 若无环,
fast先到达末尾,循环退出,返回false。 - 若有环,
fast进入环后会在环中绕圈,而slow最终也会进入环。此时fast相对于slow的速度为 1 步/次(fast每次比slow多走一步),因此fast必定能在有限步内追上slow。
复杂度分析:
- 时间复杂度: O(n),其中 n 为链表节点数。无环时只需遍历到末尾;有环时,
slow和fast相遇前遍历的步数不超过 n。 - 空间复杂度: O(1),只使用了两个指针变量,无需额外存储空间。

浙公网安备 33010602011771号