2026-02-27 05:53:51
判断链表是否有环可以通过哈希集合存储遍历节点或快慢指针两种方法实现。
一、方法一:哈希集合存储遍历节点初始化一个空的哈希集合Set<ListNode>。
从链表头节点head开始遍历:
若当前节点不在集合中,将其加入集合。
若当前节点已在集合中,返回true(有环)。
若当前节点为null,返回false(无环)。
继续遍历下一个节点,直到链表结束。
示例1:链表3→2→0→-4→2(环连接至第二个节点)。
遍历过程:3(加入集合)→2(加入集合)→0(加入集合)→-4(加入集合)→再次遇到2(已存在),返回true。
示例2:链表1→2→1(环连接至第一个节点)。
遍历过程:1(加入集合)→2(加入集合)→再次遇到1(已存在),返回true。
示例3:链表1→null(无环)。
遍历过程:1(加入集合)→next为null,返回false。

初始化慢指针slow指向头节点head,快指针fast指向head.next(若head为null则直接返回false)。
循环移动指针:
若slow与fast相遇,返回true(有环)。
更新slow为slow.next。
更新fast为fast.next.next(需先检查fast和fast.next是否为null)。
若循环结束(fast为null),返回false(无环)。
示例1:链表3→2→0→-4→2(环连接至第二个节点)。
初始状态:slow=3,fast=2。
移动过程:
第1步:slow=2,fast=0。
第2步:slow=0,fast=2。
第3步:slow=-4,fast=0。
第4步:slow=2,fast=2(相遇),返回true。
示例2:链表1→2→1(环连接至第一个节点)。
初始状态:slow=1,fast=2。
移动过程:
第1步:slow=2,fast=1。
第2步:slow=1,fast=1(相遇),返回true。
示例3:链表1→null(无环)。
初始状态:slow=1,fast=null。
直接返回false。

时间复杂度:O(n),需遍历链表一次。
空间复杂度:O(n),需存储所有节点。
时间复杂度:O(n),快指针最多移动两倍于慢指针的步数。
空间复杂度:O(1),仅需两个指针的额外空间。
推荐使用快慢指针法,因其空间效率更高,尤其适用于大规模链表。