题目描述
给你一个链表的头节点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 <= 105pos为-1或者链表中的一个有效索引。
解决方案:
这段代码的核心功能是判断单链表中是否存在环形结构(即链表的某个节点的next指向链表中之前的节点,形成闭环),采用「快慢指针(龟兔赛跑)」的经典方法实现,时间复杂度O(n)、空间复杂度O(1),是判断链表环的最优解法。
核心逻辑
代码利用快慢指针的运动特性:若链表无环,快指针会先走到末尾;若有环,快慢指针最终会在环内相遇:
- 边界预判:先判断链表为空或只有一个节点,直接返回
false(不可能有环); - 指针初始化:慢指针
low和快指针fast都从链表头节点head出发; - 快慢遍历与相遇判断:循环条件为
fast不为空且fast->next不为空(保证快指针能走两步):- 慢指针
low每次走 1 步,快指针fast每次走 2 步; - 若某一时刻
fast == low(快慢指针相遇),说明链表有环,立即返回true;
- 慢指针
- 无环返回:若循环结束(快指针走到链表末尾),说明链表无环,返回
false。
总结
- 核心思路:利用快慢指针步长差(1:2),无环则快指针先到终点,有环则快慢指针必在环内相遇;
- 关键细节:循环条件
fast && fast->next避免快指针访问空指针的next导致崩溃; - 效率优势:无需额外空间(如哈希表)存储节点,仅用两个指针完成判断,空间复杂度为
O(1)。
函数源码:
/** * 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==nullptr || head->next==nullptr){ return false; } ListNode* low=head; ListNode* fast=head; while(fast && fast->next){ low=low->next; fast=fast->next->next; if(fast==low) return true; } return false; } };