hot 100 第二十六题 26.环形链表 II

题目:

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始 )。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改链表。

示例 1:

复制代码
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

复制代码
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

复制代码
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

核心思路

快慢指针两阶段法

  1. 第一阶段:快慢指针找到相遇点(证明有环)

  2. 第二阶段:一个指针从头开始,一个从相遇点开始,再次相遇的地方就是环入口

    链表:
    1 → 2 → 3 → 4 → 5
    ↑ ↓
    └───────────┘
    环入口是节点2

题解:

java 复制代码
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) return null;
        
        // 第一阶段:快慢指针找相遇点
        ListNode slow = head;
        ListNode fast = head;
        
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                // 找到相遇点,进入第二阶段
                // 一个指针从头开始,一个从相遇点开始
                ListNode ptr1 = head;
                ListNode ptr2 = slow;
                
                while (ptr1 != ptr2) {
                    ptr1 = ptr1.next;
                    ptr2 = ptr2.next;
                }
                
                return ptr1;  // 环的入口
            }
        }
        
        return null;  // 无环
    }
}
```

## 数学原理(重要!)

### 设定变量
```
链表结构:
head → ... → 入口 → ... → 相遇点 → ... → 入口
       a步      b步      c步

a: 起点到入口的距离
b: 入口到相遇点的距离
c: 相遇点回到入口的距离
环长 L = b + c
```

### 推导过程
```
第一次相遇时:

慢指针走的距离: a + b
快指针走的距离: a + b + n * L  (n是快指针在环内转的圈数)

因为快指针速度是慢指针的2倍:
2 * (a + b) = a + b + n * L

化简:
2a + 2b = a + b + n * L
a + b = n * L
a = n * L - b
a = n * (b + c) - b
a = (n - 1) * (b + c) + c
a = (n - 1) * L + c

结论:
从起点走 a 步 = 从相遇点走 c 步 + (n-1)圈

所以:
- 一个指针从 head 出发
- 一个指针从相遇点出发
- 两者每次走1步,会在环入口相遇!
```

## 详细演示
```
链表:
3 → 2 → 0 → -4
    ↑        ↓
    └────────┘

a = 1 (head到入口:3→2)
b = 1 (入口到相遇点可能是:2→0)
c = 2 (相遇点回到入口:0→-4→2)
L = 3 (环长:2→0→-4→2)

第一阶段: 找相遇点
------------------
初始:
slow = 3
fast = 3

第1次移动:
slow: 3 → 2
fast: 3 → 2 → 0

slow = 2
fast = 0

第2次移动:
slow: 2 → 0
fast: 0 → -4 → 2

slow = 0
fast = 2

第3次移动:
slow: 0 → -4
fast: 2 → 0 → -4

slow = -4
fast = -4
相遇!

第二阶段: 找环入口
------------------
ptr1 = head = 3
ptr2 = slow = -4

第1次移动:
ptr1: 3 → 2
ptr2: -4 → 2

ptr1 = 2
ptr2 = 2
相遇!

返回 节点2(环入口)
```

## 图解过程
```
链表:
     入口
      ↓
1 → 2 → 3 → 4 → 5
    ↑           ↓
    └───────────┘

步骤1: 快慢指针找相遇点
--------------------
slow每次1步,fast每次2步

假设在节点4相遇:
    入口
      ↓
1 → 2 → 3 → 4 → 5
    ↑       ↑   ↓
    └───────┴───┘
            相遇点

步骤2: 从head和相遇点同时出发
--------------------
ptr1从1出发,ptr2从4出发,每次各走1步

ptr1: 1 → 2
ptr2: 4 → 5 → 2
          ↑
      相遇在入口!
```

## 为什么第二阶段要这样走?

### 直观理解
```
验证数学推导 a = c + (n-1)L:

从head到入口的距离 = a
从相遇点绕环回到入口的距离 = c

因为 a = c + (n-1)L
所以从head走a步到入口
  = 从相遇点走c步到入口 + 再转(n-1)圈

两个指针每次都走1步:
- ptr1走a步到达入口
- ptr2走c步+(n-1)圈也到达入口
- 所以两者在入口相遇!
```

### 特殊情况:n=1
```
当快指针只转了1圈就相遇(最常见):
a = c

这时:
- 从head走到入口的距离
- 等于从相遇点走到入口的距离
- 两者必然同时到达入口
```

## 完整示例

### 示例1
```
链表:
3 → 2 → 0 → -4
    ↑        ↓
    └────────┘

第一阶段:
slow和fast在某处相遇(假设在-4)

第二阶段:
ptr1从3开始: 3 → 2
ptr2从-4开始: -4 → 2

在节点2相遇 ✓(环入口)
```

### 示例2
```
链表:
1 → 2
↑   ↓
└───┘

第一阶段:
slow和fast在2相遇

第二阶段:
ptr1从1开始: 1
ptr2从2开始: 2 → 1

在节点1相遇 ✓(环入口)
```

### 示例3(无环)
```
链表: 1 → 2 → 3 → null

第一阶段:
fast到达null,没有相遇
直接返回 null
相关推荐
啊阿狸不会拉杆2 小时前
《机器学习导论》第 16 章-贝叶斯估计
人工智能·python·算法·机器学习·ai·参数估计·贝叶斯估计
ArturiaZ3 小时前
【day27】
算法
望舒5133 小时前
代码随想录day32,动态规划part1
java·算法·leetcode·动态规划
楠秋9203 小时前
代码随想录算法训练营第三十二天| 509. 斐波那契数 、 70. 爬楼梯 、746. 使用最小花费爬楼梯
数据结构·算法·leetcode·动态规划
㓗冽3 小时前
最大效益(二维数组)-基础题76th + 螺旋方阵(二维数组)-基础题77th + 方块转换(二维数组)-基础题78th
数据结构·算法
Ivanqhz3 小时前
数据流分析的核心格(Lattice)系统
开发语言·javascript·后端·python·算法·蓝桥杯·rust
琛説3 小时前
⚡PitchPPT:将PPT导出为高清全图PPT,并控制PPT文件大小在固定MB/GB以内【解析算法原理 · 作者谈】
windows·python·算法·github·powerpoint
We་ct3 小时前
LeetCode 25. K个一组翻转链表:两种解法详解+避坑指南
前端·算法·leetcode·链表·typescript
Hag_203 小时前
LeetCode Hot100 438.找到字符串中的所有字母异位词
算法·leetcode·职场和发展