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 📝)
1. Problem Link 🔗
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^5posis-1or 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. Solution 1: Floyd's Tortoise and Hare (Mathematical Approach) - Recommended
3.1. Algorithm
- Use slow and fast pointers to detect if a cycle exists
- When they meet, reset slow pointer to head
- Move both pointers one step at a time until they meet again
- 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 entryb= distance from cycle entry to meeting pointc= 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.