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.

相关推荐
苦瓜小生7 分钟前
【前端】|【js手撕】经典高频面试题:手写实现function.call、apply、bind
java·前端·javascript
Wilber的技术分享11 分钟前
【LeetCode高频手撕题 2】面试中常见的手撕算法题(小红书)
笔记·算法·leetcode·面试
邪神与厨二病14 分钟前
Problem L. ZZUPC
c++·数学·算法·前缀和
NGC_661142 分钟前
Java 线程池:execute () 和 submit () 到底有什么区别?
java
cngm11044 分钟前
解决麒麟v10下tomcat无法自动启动的问题
java·tomcat
色空大师1 小时前
【网站搭建实操(一)环境部署】
java·linux·数据库·mysql·网站搭建
客卿1231 小时前
牛客刷题--找数字-- 字符串检测-字符串 双指针
java·开发语言
烛之武1 小时前
SpringBoot基础
java·spring boot·后端
软件测试媛1 小时前
软件测试常见的面试题(46道)
功能测试·面试·职场和发展
梯度下降中1 小时前
LoRA原理精讲
人工智能·算法·机器学习