XingHuiSamaの宝藏之地
首页项目归档照片墙音乐灵境说说杂谈友链关于
封面

Leetcode一百题——环形链表

2026-04-21 09:28:33
# Leetcode
# C++
# 题解
# 工作

给你一个链表的头节点 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
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引 。

**进阶:**你能用 O(1)(即,常量)内存解决此问题吗?

1. 算法核心思想:Floyd 判圈算法

判断链表是否有环的经典方法是“快慢指针法”(类似于操场跑道上的追及问题)。 设置两个指针,起点都在链表头部。慢指针(slow)每次走一步,快指针(fast)每次走两步。

  • 如果链表没有环:快指针会率先到达链表的尾部(NULL)。
  • 如果链表有环:快指针会先进入环内绕圈。当慢指针也进入环内后,由于快指针的速度比慢指针快 1,快指针最终一定会追上并与慢指针重合。

2. 逻辑拆解

  • 起步错位处理: 由于初始化时 slow 和 fast 都指向 head,如果直接将 slow != fast 写在 while 循环条件中,循环一开始就不会执行。因此,代码在进入循环前,先手动让 fast 走两步、slow 走一步。在这个过程中,顺便处理了空链表或单节点链表的边界情况(直接返回 false)。
  • 循环追击: while 循环的条件严格限制了指针的安全运行范围(fast != NULL && fast->next != NULL),防止在步进过程中发生空指针越界访问。在循环体内,严格保持慢指针单步、快指针双步的移动频率。
  • 状态识别与返回: 当 while 循环结束时,只有两种可能的情况:
  • 快指针触碰到了链表边界(fast == NULL 或 fast->next == NULL),这表明链表存在物理终点,直接返回 false。
  • 上述条件不成立,说明循环是因为 slow == fast 被打破的,即快慢指针在环内相遇,返回 true。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;


        
        if (fast!= NULL && fast->next != NULL) {
            fast = fast->next->next;
        }
        else {
            return false;
        }
        slow = slow->next;
        while (slow != fast && fast != NULL && fast->next != NULL) {
            slow = slow->next;
            if (fast->next != NULL) {
                fast = fast->next->next;
            }
            else {
                fast = fast->next;
            }
        }

        if (fast == NULL || fast->next == NULL) {
            return false;
        }
        return true;
    }
};

3. 复杂度分析

  • 时间复杂度:O(N)。其中 N 是链表中的节点数。
  • 当链表无环时,快指针走完一半的节点数即可到达末尾,时间开销为线性。
  • 当链表有环时,慢指针进入环后,快指针追赶慢指针所需的相对距离不会超过环的长度。整体循环次数依然与节点总数成正比。
  • 空间复杂度:O(1)。算法仅维护了 slow 和 fast 两个节点指针,未申请任何与数据规模相关的额外内存空间。
avatar

XingHuiSama

在代码、学术与分子动力学模拟间穿梭的普通人。近期正埋头于 GROMACS 模拟研究与神经网络计算。

RECOMMENDED

GROMACS 2025 分子动力学模拟初探2222

2026-03-24 07:00:45

Computational Chemistry Tool 工具二介绍

2026-04-01 07:00:23

Leetcode一百题——字母异位词分组

2026-04-07 15:34:18

Table of Contents