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.

相关推荐
南境十里·墨染春水5 小时前
C++ 笔记 thread
java·开发语言·c++·笔记·学习
南境十里·墨染春水5 小时前
C++ 笔记 高级线程同步原语与线程池实现
java·开发语言·c++·笔记·学习
阿巴斯甜5 小时前
Predicate的使用:
java
阿巴斯甜5 小时前
Supplier的使用:
java
阿巴斯甜6 小时前
Function 用法:
java
做个文艺程序员6 小时前
流式输出(SSE)在 Spring Boot 中的实现【OpenClAW + Spring Boot 系列 第3篇】
java·spring boot·后端
逻辑驱动的ken6 小时前
Java高频面试考点场景题09
java·开发语言·数据库·算法·oracle·哈希算法·散列表
小手cool6 小时前
如何在Java中根据另一个配对集合对一个集合进行排序
java·开发语言
云烟成雨TD6 小时前
Spring AI Alibaba 1.x 系列【28】Nacos Skill 管理中心功能说明
java·人工智能·spring
升鲜宝供应链及收银系统源代码服务6 小时前
OMS 订单模块重构正式文档(一)---升鲜宝生鲜配送供应链管理系统
java·开发语言·重构·生鲜配送源代码·生鲜供应链源代码