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.

相关推荐
练习时长一年6 小时前
LeetCode热题100(杨辉三角)
算法·leetcode·职场和发展
lzllzz236 小时前
bellman_ford算法
算法
栈与堆6 小时前
LeetCode 19 - 删除链表的倒数第N个节点
java·开发语言·数据结构·python·算法·leetcode·链表
sunfove6 小时前
麦克斯韦方程组 (Maxwell‘s Equations) 的完整推导
线性代数·算法·矩阵
一路向北·重庆分伦6 小时前
03-01:MQ常见问题梳理
java·开发语言
一 乐6 小时前
绿色农产品销售|基于springboot + vue绿色农产品销售系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·宠物
lhrimperial7 小时前
企业智能知识库助手落地实践:从RAG到Multi-Agent
java·spring cloud·微服务·系统架构·知识图谱
Rui_Freely7 小时前
Vins-Fusion之 SFM准备篇(十二)
人工智能·算法·计算机视觉
3***68847 小时前
Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程
java·spring boot·后端
C***u1767 小时前
Spring Boot问题总结
java·spring boot·后端