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.

相关推荐
weixin_440784113 小时前
【HandlerThread实现原理】
android·java·开发语言
leoZ2313 小时前
本地跑大模型实战(七):llama.cpp 性能调优,让推理更快更省
java·人工智能·spring·生成对抗网络·语言模型·自然语言处理·llama
阿坤带你走近大数据3 小时前
基金面试准备1
面试·职场和发展
mubei-1235 小时前
SpringDAO的用法
java·开发语言·数据库
happymagic5 小时前
java spring boot做的jar包程序,如何实现自动运行启动
java·运维·服务器·spring boot·jar
小程故事多_805 小时前
从A2C、TRPO、PPO到GRPO,强化学习策略梯度算法完整演进与大模型落地实战解析
人工智能·算法
2601_956121977 小时前
二分算法(知识点+题目)
c++·算法
都叫我大帅哥7 小时前
给 Java 程序员的 CSRF 攻击详解:从原理到防御实战
java
江南十四行7 小时前
Spring框架核心(上)——IoC控制反转与DI依赖注入详解
java·后端·spring
fb_123458 小时前
Linux磁盘分区从入门到实操:MBR_GPT全解析+分区工具实战指南
java·linux·gpt