跳至内容
返回

LeetCode 141 - 环形链表

发布于:  at  04:53 下午

题目

给定链表头节点 head,判断链表中是否存在环。如果存在环则返回 true,否则返回 false

示例:

有环情况:

 3 → 2 → 0 → -4
     ↑       ↓
     └───────┘

无环情况:

 1 → 2 → 3 → null

解题思路

使用快慢指针(Floyd 判圈算法)来检测链表是否有环。

核心原理

设置两个指针:

从同一起点出发,如果链表有环,快指针最终会在环内追上慢指针;如果无环,快指针会先到达链表末尾(null)。

为什么快慢指针一定会相遇?

如果有环,快指针进入环后,每次循环都会缩短与慢指针的距离 1 步,所以必然会相遇。可以理解为:在环形跑道上,跑得快的人一定会追上跑得慢的人。

代码实现

 public class Solution {
     public boolean hasCycle(ListNode head) {
         // slow: 慢指针,每次走 1 步
         // fast: 快指针,每次走 2 步
         ListNode slow = head;
         ListNode fast = head;
 ​
         // 循环条件必须保护 fast.next 和 fast.next.next 不为空
         // 否则执行 fast = fast.next.next 时会空指针异常
         while (fast != null && fast.next != null) {
             slow = slow.next;
             fast = fast.next.next;
 ​
             // 使用 == 判断是否是同一个节点对象
             // 不能用 val 比较,因为不同节点值可能相同
             if (slow == fast) {
                 return true;
             }
         }
 ​
         return false;
     }
 }

代码解释

  1. 初始化双指针:slow 和 fast 都从 head 开始
  2. 循环条件fast != null && fast.next != null 确保可以安全执行 fast.next.next
  3. 指针移动:slow 走 1 步,fast 走 2 步
  4. 相遇检测:用 == 比较节点引用(不是比较值),相同则有环
  5. 退出循环:fast 到达 null 说明无环,返回 false

执行过程示例

以有环链表为例:

 初始: slow=3, fast=3
 ​
 第1轮:
   slow = slow.next      → slow=2
   fast = fast.next.next → fast=0
 ​
 第2轮:
   slow = slow.next      → slow=0
   fast = fast.next.next → fast=2
 ​
 第3轮:
   slow = slow.next      → slow=-4
   fast = fast.next.next → fast=-4
 ​
 slow == fast,返回 true

速记

快慢指针同起点,慢走 1 步快走 2 步,有环必相遇,无环快指针先到 null。

注意点

  1. 循环条件必须是 fast != null && fast.next != null:保护 fast.next.next 不会空指针
  2. 使用 == 比较节点:比较的是引用地址,不是节点值,因为不同节点可能有相同的值
  3. 不能只判断 fast != null:会导致 fast.next.next 空指针异常
  4. 初始化位置:两个指针都从 head 开始,不需要错开

复杂度分析


建议修改
在以下平台分享此文章:

上一篇
LeetCode 160 - 相交链表
下一篇
LeetCode 23 - 合并 K 个升序链表