题目描述
给你一个链表的头节点
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)
(即,常量)内存解决此问题吗?
解题思路
判断链表中是否有环,可以使用一种高效的算法,即 Floyd 的兔子和乌龟算法(也叫做 快慢指针算法),可以在 O(n) 时间复杂度和 O(1) 空间复杂度下解决问题:
-
使用快慢指针:
初始化两个指针,slow
和fast
。slow
每次移动一个节点,fast
每次移动两个节点;如果链表中存在环,那么slow
和fast
会在环中相遇;如果链表中没有环,fast
指针会到达链表末尾(即fast
或fast.next
变为null
)。 -
过程:
初始化slow
和fast
指针都指向链表的头节点;遍历链表,移动指针:fast
移动到下两个节点。slow
移动到下一个节点。如果slow
和fast
指针在某一时刻相遇,链表中存在环。如果fast
指针到达链表的末尾,链表中没有环。
复杂度分析
- 时间复杂度: O(n)。每个节点最多访问两次,分别是快指针和慢指针的访问。
- 空间复杂度: O(1)。只使用了常量级别的额外空间(两个指针)。
代码实现
package org.zyf.javabasic.letcode.hot100.list;
import org.zyf.javabasic.letcode.list.base.ListNode;
/**
* @program: zyfboot-javabasic
* @description: 环形链表
* @author: zhangyanfeng
* @create: 2024-08-22 00:12
**/
public class HasCycleSolution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false; // 空链表或只有一个节点的链表不可能有环
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next; // 慢指针每次移动一个节点
fast = fast.next.next; // 快指针每次移动两个节点
if (slow == fast) { // 快慢指针相遇,说明链表有环
return true;
}
}
return false; // 快指针到达链表末尾,说明链表没有环
}
public static void main(String[] args) {
HasCycleSolution solution = new HasCycleSolution();
// 测试用例 1: 有环的链表
ListNode head1 = new ListNode(3);
head1.next = new ListNode(2);
head1.next.next = new ListNode(0);
head1.next.next.next = new ListNode(-4);
head1.next.next.next.next = head1.next; // 尾部连接到第二个节点
System.out.println("Test Case 1: " + solution.hasCycle(head1)); // 应该输出 true
// 测试用例 2: 有环的链表
ListNode head2 = new ListNode(1);
head2.next = new ListNode(2);
head2.next.next = head2; // 尾部连接到第一个节点
System.out.println("Test Case 2: " + solution.hasCycle(head2)); // 应该输出 true
// 测试用例 3: 无环的链表
ListNode head3 = new ListNode(1);
System.out.println("Test Case 3: " + solution.hasCycle(head3)); // 应该输出 false
}
}
具体可参考:https://zyfcodes.blog.csdn.net/article/details/141401712