力扣hot100-141.环形链表

这是一个经典的链表问题,通常被称为"判断链表是否有环"。

解决这个问题的标准且最高效的解法是 快慢指针算法(也称为 Floyd 判圈算法或龟兔赛跑算法)。

解题思路

  1. 定义两个指针

    • 慢指针 (slow):一次走一步。

    • 快指针 (fast):一次走两步。

  2. 逻辑分析

    • 如果没有环fast 指针走得快,最终会遇到 NULL(即到达链表末尾),此时可以直接返回 false

    • 如果有环fast 指针会率先进入环,并在环内循环。当 slow 指针也进入环后,这就变成了一个"追及问题"。因为 fastslow 每次多走一步,所以在有限的步数内,fast 一定会追上 slow(即 fast == slow)。

  3. 复杂度

    • 时间复杂度O(n)。如果无环,遍历一次;如果有环,快指针在环内绕圈追上慢指针的时间也是线性的。

    • 空间复杂度O(1)。只使用了两个指针,不需要额外的哈希表来存储已访问的节点。

下面是完整的代码实现,包含了解题类和用于构建带环链表进行测试的 main 函数。

代码要点

  1. 初始化slowfast 都指向 head。有些写法会让 fast 初始指向 head->next,这也是可以的,但循环条件和判断逻辑稍微不同。让它们都从 head 开始是最直观的。

  2. 循环条件while (fast != NULL && fast->next != NULL)。这个条件非常关键,它保证了 fast->next->next 不会出现空指针异常。

  3. 相遇判断 :在移动指针之后立即检查 if (slow == fast)。如果相等,说明快指针追上了慢指针,链表有环。

  4. 返回结果:如果循环正常退出,说明快指针遇到了空指针,链表没有环。

cpp 复制代码
/**
 * 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) {
        if(head == NULL ||  head->next == NULL)
            return false;
        
        ListNode* fast = head;
        ListNode* slow = head;
        
        while(fast != nullptr && fast->next != nullptr)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)
                return true;
        }

        return false;
    }
};
相关推荐
地平线开发者6 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮6 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者7 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考7 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx10 小时前
CART决策树基本原理
算法·机器学习
Wect11 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱11 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
Gorway18 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风18 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect18 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript