LeetCode 142: Linked List Cycle II

LeetCode 142: Linked List Cycle II

    • [1. Problem Link 🔗](#1. Problem Link 🔗)
    • [2. Solution Overview 🧭](#2. Solution Overview 🧭)
    • [3. Solution 1: Floyd's Tortoise and Hare (Mathematical Approach) - Recommended](#3. Solution 1: Floyd's Tortoise and Hare (Mathematical Approach) - Recommended)
      • [3.1. Algorithm](#3.1. Algorithm)
      • [3.2. Important Points](#3.2. Important Points)
      • [3.3. Java Implementation](#3.3. Java Implementation)
      • [3.4. Time & Space Complexity](#3.4. Time & Space Complexity)
    • [4. Solution 2: Hash Set Approach](#4. Solution 2: Hash Set Approach)
      • [4.1. Algorithm思路](#4.1. Algorithm思路)
      • [4.2. Important Points](#4.2. Important Points)
      • [4.3. Java Implementation](#4.3. Java Implementation)
      • [4.4. Time & Space Complexity](#4.4. Time & Space Complexity)
    • [5. Solution 3: Node Marking (Destructive)](#5. Solution 3: Node Marking (Destructive))
      • [5.1. Algorithm思路](#5.1. Algorithm思路)
      • [5.2. Important Points](#5.2. Important Points)
      • [5.3. Java Implementation](#5.3. Java Implementation)
      • [5.4. Time & Space Complexity](#5.4. Time & Space Complexity)
    • [6. Solution 4: Two-Pass Floyd's Algorithm](#6. Solution 4: Two-Pass Floyd's Algorithm)
      • [6.1. Algorithm思路](#6.1. Algorithm思路)
      • [6.2. Important Points](#6.2. Important Points)
      • [6.3. Java Implementation](#6.3. Java Implementation)
      • [6.4. Time & Space Complexity](#6.4. Time & Space Complexity)
    • [7. Solution 5: Optimized Floyd's with Early Check](#7. Solution 5: Optimized Floyd's with Early Check)
      • [7.1. Algorithm思路](#7.1. Algorithm思路)
      • [7.2. Important Points](#7.2. Important Points)
      • [7.3. Java Implementation](#7.3. Java Implementation)
      • [7.4. Time & Space Complexity](#7.4. Time & Space Complexity)
    • [8. Mathematical Proof (Why Solution 1 Works)](#8. Mathematical Proof (Why Solution 1 Works))
    • [9. Solution Comparison 📊](#9. Solution Comparison 📊)
    • [10. Summary 📝](#10. Summary 📝)

LeetCode 142: Linked List Cycle II

2. Solution Overview 🧭

Given the head of a linked list, return the node where the cycle begins. If there is no cycle, return null.

This is the follow-up problem to Linked List Cycle (LeetCode 141), where we not only detect but also find the exact starting point of the cycle.

Example:

复制代码
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle where the tail connects to the 2nd node.

Constraints:

  • The number of nodes in the list is in the range [0, 10^4]
  • -10^5 <= Node.val <= 10^5
  • pos is -1 or a valid index in the linked-list

Common approaches include:

  • Floyd's Cycle Detection with Mathematical Proof: Use slow and fast pointers with additional logic
  • Hash Set: Store visited nodes and return first duplicate
  • Two-Pass Floyd's: First detect cycle, then find entry point

3.1. Algorithm

  1. Use slow and fast pointers to detect if a cycle exists
  2. When they meet, reset slow pointer to head
  3. Move both pointers one step at a time until they meet again
  4. The meeting point is the cycle entry point

3.2. Important Points

  • Based on mathematical proof: distance from head to entry = distance from meeting point to entry
  • O(1) space complexity
  • Most efficient approach

3.3. Java Implementation

java 复制代码
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        
        ListNode slow = head;
        ListNode fast = head;
        
        // Step 1: Detect if cycle exists
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                // Cycle detected, now find entry point
                break;
            }
        }
        
        // No cycle found
        if (fast == null || fast.next == null) {
            return null;
        }
        
        // Step 2: Find cycle entry point
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        
        return slow; // Entry point of cycle
    }
}

3.4. Time & Space Complexity

  • Time Complexity: O(n)
  • Space Complexity: O(1)

4. Solution 2: Hash Set Approach

4.1. Algorithm思路

  • Traverse the list and store each node in a hash set
  • The first node that appears twice is the cycle entry point
  • Simple and intuitive approach

4.2. Important Points

  • Easy to understand and implement
  • Uses O(n) extra space
  • Straightforward logic

4.3. Java Implementation

java 复制代码
import java.util.HashSet;

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        
        HashSet<ListNode> visited = new HashSet<>();
        ListNode current = head;
        
        while (current != null) {
            if (visited.contains(current)) {
                return current; // First duplicate node is cycle entry
            }
            visited.add(current);
            current = current.next;
        }
        
        return null; // No cycle found
    }
}

4.4. Time & Space Complexity

  • Time Complexity: O(n)
  • Space Complexity: O(n)

5. Solution 3: Node Marking (Destructive)

5.1. Algorithm思路

  • Modify visited nodes by setting a special marker
  • The first node that's already marked is the cycle entry
  • This approach modifies the original list

5.2. Important Points

  • O(1) space complexity
  • Modifies the original list
  • Not recommended for production

5.3. Java Implementation

java 复制代码
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        
        ListNode current = head;
        int MARKER = Integer.MIN_VALUE;
        
        while (current != null) {
            if (current.val == MARKER) {
                return current; // First marked node is cycle entry
            }
            current.val = MARKER;
            current = current.next;
        }
        
        return null; // No cycle found
    }
}

5.4. Time & Space Complexity

  • Time Complexity: O(n)
  • Space Complexity: O(1)

6. Solution 4: Two-Pass Floyd's Algorithm

6.1. Algorithm思路

  • First pass: Detect cycle and count cycle length
  • Second pass: Use two pointers separated by cycle length to find entry
  • More explicit but same complexity

6.2. Important Points

  • Alternative implementation of Floyd's algorithm
  • More steps but clearer logic
  • Same time and space complexity

6.3. Java Implementation

java 复制代码
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        
        // Step 1: Detect cycle and find meeting point
        ListNode meetingPoint = getMeetingPoint(head);
        if (meetingPoint == null) {
            return null; // No cycle
        }
        
        // Step 2: Calculate cycle length
        int cycleLength = getCycleLength(meetingPoint);
        
        // Step 3: Find cycle entry
        return findCycleEntry(head, cycleLength);
    }
    
    private ListNode getMeetingPoint(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                return slow;
            }
        }
        
        return null;
    }
    
    private int getCycleLength(ListNode meetingPoint) {
        int length = 1;
        ListNode current = meetingPoint.next;
        
        while (current != meetingPoint) {
            length++;
            current = current.next;
        }
        
        return length;
    }
    
    private ListNode findCycleEntry(ListNode head, int cycleLength) {
        ListNode front = head;
        ListNode back = head;
        
        // Move front pointer cycleLength steps ahead
        for (int i = 0; i < cycleLength; i++) {
            front = front.next;
        }
        
        // Move both until they meet
        while (front != back) {
            front = front.next;
            back = back.next;
        }
        
        return front; // Entry point
    }
}

6.4. Time & Space Complexity

  • Time Complexity: O(n)
  • Space Complexity: O(1)

7. Solution 5: Optimized Floyd's with Early Check

7.1. Algorithm思路

  • Optimized version of Floyd's algorithm
  • Combine cycle detection and entry finding in one pass when possible
  • Handle edge cases more efficiently

7.2. Important Points

  • More efficient for certain cases
  • Cleaner code structure
  • Same mathematical foundation

7.3. Java Implementation

java 复制代码
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        
        ListNode slow = head;
        ListNode fast = head;
        
        // Detect cycle
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            
            if (slow == fast) {
                // Found cycle, now find entry
                slow = head;
                while (slow != fast) {
                    slow = slow.next;
                    fast = fast.next;
                }
                return slow;
            }
        }
        
        return null;
    }
}

7.4. Time & Space Complexity

  • Time Complexity: O(n)
  • Space Complexity: O(1)

8. Mathematical Proof (Why Solution 1 Works)

Let:

  • a = distance from head to cycle entry
  • b = distance from cycle entry to meeting point
  • c = distance from meeting point to cycle entry
  • Cycle length = b + c

When slow and fast meet:

  • Slow distance = a + b
  • Fast distance = a + b + n(b + c) (n = number of cycles)

Since fast is twice as fast:
2(a + b) = a + b + n(b + c)
a + b = n(b + c)
a = n(b + c) - b
a = (n-1)(b + c) + c

This shows that distance from head to entry equals distance from meeting point to entry plus integer cycles.

9. Solution Comparison 📊

Solution Time Complexity Space Complexity Advantages Disadvantages
Floyd's Algorithm O(n) O(1) Optimal, mathematical Requires understanding proof
Hash Set O(n) O(n) Simple, intuitive Extra space usage
Node Marking O(n) O(1) No extra structures Modifies original list
Two-Pass Floyd's O(n) O(1) Clear step-by-step More code
Optimized Floyd's O(n) O(1) Efficient, clean Same as basic Floyd's

10. Summary 📝

  • Key Insight: The distance from head to cycle entry equals the distance from meeting point to cycle entry
  • Recommended Approach: Solution 1 (Floyd's Algorithm) is the gold standard
  • Mathematical Foundation: The algorithm is backed by solid mathematical proof
  • Pattern Recognition: This extends the basic cycle detection pattern with additional logic for entry point

Interview Tip: Be prepared to explain the mathematical reasoning behind Floyd's algorithm, as this demonstrates deep understanding of the problem.

相关推荐
罗湖老棍子4 小时前
Biorhythms(信息学奥赛一本通- P1639)
算法·数论·裴蜀定理·扩展欧几里得·扩展中国剩余定理
panxianren7 小时前
Bun 1.4 的 bun test --parallel 将 4 秒的测试套件缩短到约 1 秒
java·javascript
sunshine22 girl9 小时前
Java学习七 Java 项目实战2-注册业务
java·学习
奋发向前wcx9 小时前
CSP-J复赛模拟赛4 王晨旭补题 2026.10.5
算法
省钱兄--zs9 小时前
北京24小时自助健身房系统软件开发实战:从架构设计到部署指南
java·数据仓库·spring boot·小程序·需求分析
youdexiang9 小时前
Android录音软件时间关键词检索功能分析
java·人工智能
sunshine22 girl10 小时前
Java学习七 Java 项目实战1-项目创建和主页面搭建
java·开发语言·学习
code2cat10 小时前
Java进阶篇之AtomicStampedReference:引用回到原值,版本戳仍能记住变化
java·cas·并发编程·aba
念何架构之路11 小时前
zap采样器与性能优化内幕
算法·性能优化·哈希算法
泡茶喝茶写代码12 小时前
A股量化数据工程:从 REST 接口到策略信号(第 8 篇):成长能力因子:营收与利润增速
java·python·股票数据api·股票数据api接口·股票量化数据api·股票量化数据接口·股票数据api数据