75. Linked List Cycle II
๐ LeetCode Problem: 142. Linked List Cycle II
๐ Difficulty: Medium
๐ท๏ธ Topics: Hash Table, Linked List, Two Pointers
Problem Statement
Given the head of a linked list, return the node where the cycle begins. If there is no cycle, return null.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to (0-indexed). It is -1 if there is no cycle. Note that pos is not passed as a parameter.
Do not modify the linked list.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where the tail connects to the second node.
Visual:
3 -> 2 -> 0 -> -4
โ โ
โโโโโโโโโโโโ
Cycle starts here!
Example 2:
Input: head = [1,2], pos = 0
Output: tail connects to node index 0
Explanation: There is a cycle in the linked list, where the tail connects to the first node.
Visual:
1 -> 2
โ โ
โโโโโโ
Cycle starts at head!
Example 3:
Input: head = [1], pos = -1
Output: no cycle
Explanation: There is no cycle in the linked list.
Visual:
1 -> null
Constraints:
- The number of the 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.
Follow up: Can you solve it using O(1) (i.e. constant) memory?
๐ ELI5 (Explain Like I'm 5) - START HERE!
Imagine you and your friend are on a circular track:
The Track:
START โโโโโโโโโโ> LOOP ENTRANCE โโโโโโโ> around the loop
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโ
You start at START.
Your friend runs 2x faster than you.
You both eventually meet somewhere ON THE LOOP.
The Question: Where is the LOOP ENTRANCE?
The Magic Trick:
Step 1: You and friend run until you meet (friend is faster).
You meet somewhere on the loop.
Step 2: YOU go back to START.
FRIEND stays where you met.
Step 3: Now BOTH run at the SAME SPEED.
When you meet again โ that's the LOOP ENTRANCE!
Why does this work?
Because of the speeds, when you meet the first time,
you're positioned such that:
- Distance from START to LOOP ENTRANCE
- Equals distance from WHERE-YOU-MET to LOOP ENTRANCE
So walking the same speed, you both reach LOOP ENTRANCE together!
In Linked List terms:
The "track" is the linked list.
The "loop" is the cycle.
The "loop entrance" is the cycle start (what we want to find!).
Phase 1: Fast and slow pointers meet in the cycle.
Phase 2: Reset one to start, both walk same speed โ meet at cycle start!
That's it! The entire algorithm! Now let's see the details...
๐จ Visual Understanding
The Problem Visualized
Example 1: Cycle starts at node 2
List: 3 -> 2 -> 0 -> -4
L โ โ
โโโโโโโโโโโโ
C = cycle start
L = distance from head to cycle start = 1
C = cycle length = 3 (nodes: 2, 0, -4)
The Challenge: Find WHERE cycle starts
Easy: Detect IF there's a cycle (Problem #71)
Use fast & slow pointers
If they meet โ cycle exists โ
Hard: Find WHERE cycle begins
Meeting point != cycle start!
Need mathematical insight! ๐งฎ
Key Insight:
When fast and slow meet:
They meet INSIDE the cycle
But NOT necessarily at cycle start!
Example:
3 -> 2 -> 0 -> -4
โ โ
โโโโโโโโโโโโ
They might meet at node 0 or -4
Not at cycle start (node 2)!
How to find cycle start from meeting point? ๐ค
๐จ CRITICAL INSIGHT - The Mathematical Proof!
The Key Pattern!
Floyd's Algorithm - Phase 2
Phase 1: Detect cycle (fast & slow meet)
slow and fast meet at some point in cycle
Phase 2: Find cycle start
Reset slow to head
Keep fast at meeting point
Move BOTH at SAME SPEED (1 step each)
They meet at CYCLE START! โ
Why does this work? MATHEMATICS! ๐งฎ
The Intuition Behind Phase 2 (CRITICAL!)
Let's build understanding step by step!
INTUITION 1: What do we know after Phase 1?
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
After Phase 1, we found that slow and fast meet at some point.
Let's call this the "meeting point".
Question: WHERE is the meeting point?
Answer: Somewhere INSIDE the cycle, but we don't know where!
The key insight: The meeting point has a special relationship
with the cycle start! Let's discover it...
INTUITION 2: Let's name the distances
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Draw the list mentally:
HEAD โโ(L steps)โโ> CYCLE START โโ(k steps)โโ> MEETING POINT
โ โ
โโโโโโโโโโโโ(C-k steps)โโโโโโโโโโโ
L = distance from HEAD to CYCLE START
k = distance from CYCLE START to MEETING POINT
C = total cycle length
The cycle has C nodes total.
From MEETING POINT back to CYCLE START: (C - k) steps
INTUITION 3: How far did each pointer travel?
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Slow pointer traveled: L + k
- L steps to reach cycle start
- k steps into the cycle to reach meeting point
Fast pointer traveled: ?
- Fast also traveled L steps to reach cycle start
- Then it went around the cycle (maybe multiple times)
- And ended up at the meeting point
So fast traveled: L + nC + k
where n = number of complete cycles fast made
(n โฅ 1, because fast is faster!)
Key fact: Fast moves TWICE as fast as slow
Fast distance = 2 ร Slow distance
L + nC + k = 2 ร (L + k)
INTUITION 4: Solve the equation!
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Let's solve: L + nC + k = 2(L + k)
Expand: L + nC + k = 2L + 2k
Subtract L: nC + k = L + 2k
Subtract k: nC = L + k
Rearrange: L = nC - k โ THE MAGIC EQUATION!
But what does this MEAN? Let's visualize...
INTUITION 5: What does L = nC - k mean visually?
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
L = nC - k can be rewritten as:
L = (n-1)C + (C - k)
Let's think about what (C - k) is:
k = distance from cycle start to meeting point
C = full cycle length
C - k = remaining distance from meeting to cycle start!
Visual:
CYCLE START โโk stepsโโ> MEETING โโ(C-k) stepsโโ> back to START
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
So the equation tells us:
Distance from HEAD to CYCLE START = L
Distance from MEETING to CYCLE START = C - k (going forward)
And: L = nC - k = (n-1)C + (C-k)
This means:
Starting from HEAD: Walk L steps โ reach CYCLE START
Starting from MEETING: Walk (C-k) steps โ reach CYCLE START
But we need them to be EQUAL for our algorithm!
INTUITION 6: The AHA moment! ๐ฏ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Here's the key insight:
L = nC - k
This can be rewritten as:
L = (n-1)C + (C - k)
What does this mean?
If I start at MEETING and walk L steps:
- First I go (C - k) steps to reach cycle start
- Then I go around the cycle (n-1) complete times
- I end up back at cycle start!
If I start at HEAD and walk L steps:
- I reach cycle start for the first time!
Both pointers walk L steps and meet at CYCLE START! โ
Visual proof:
HEAD โโโโโโL stepsโโโโโโ> CYCLE START
MEETING โโ(C-k)โโ> CYCLE START โโ(n-1) complete cyclesโโ> CYCLE START
โโโโโโโโโโโโโโโโโโโโL steps totalโโโโโโโโโโโโโโโโโโโโโโโโโโ>
They meet at the SAME place! โ
INTUITION 7: Simplified understanding
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Don't worry about the math! Here's the simple version:
After Phase 1, the meeting point is positioned such that:
- Distance from HEAD to cycle start
- Equals distance from MEETING to cycle start (going forward)
Why? Because of how fast and slow pointers work!
So the algorithm:
1. Reset slow to HEAD
2. Keep fast at MEETING
3. Move BOTH at SAME speed (1 step each)
4. When they meet โ that's the CYCLE START!
Why same speed? Because distances are equal now!
INTUITION 8: Concrete example
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
List: 1 -> 2 -> 3 -> 4 -> 5 -> 6
โ โ
โโโโโโโโโโโโโโโโ
Let's say they meet at node 5.
Count distances:
HEAD(1) to CYCLE START(3): 2 steps โ L = 2
CYCLE START(3) to MEETING(5): 2 steps โ k = 2
Cycle length: 4 (nodes 3, 4, 5, 6) โ C = 4
Check: L = nC - k?
2 = nร4 - 2
2 = 4 - 2 (when n = 1) โ
Distance from MEETING(5) to CYCLE START(3):
5 -> 6 -> 3 = 2 steps = (C - k) = 4 - 2 = 2 โ
So:
From HEAD(1) to CYCLE START(3): 2 steps
From MEETING(5) to CYCLE START(3): 2 steps
Equal! So if we walk both at same speed:
Step 1: slow at 2, fast at 6
Step 2: slow at 3, fast at 3
They meet at 3 = CYCLE START! โ
INTUITION 9: Why it always works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The beauty of this algorithm:
You don't need to know L, k, C, or n!
The physics of fast & slow pointers GUARANTEES
that when they meet, the distances will be equal.
So just:
1. Run Phase 1 to find meeting point
2. Reset one pointer to head
3. Move both at same speed
4. They WILL meet at cycle start!
It's guaranteed by mathematics! โ
๐จ SIMPLE VISUAL WALKTHROUGH (Start Here!)
Let's understand this problem with a concrete example!
Example List:
1 -> 2 -> 3 -> 4 -> 5
โ โ
โโโโโโโโโโโโโโโโ
The cycle starts at node 2.
Our goal: Find node 2!
STEP-BY-STEP WALKTHROUGH:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
PHASE 1: Detect the cycle (we know how to do this!)
Start: slow = 1, fast = 1
Move 1: slow = 2 (1 step)
fast = 3 (2 steps)
Move 2: slow = 3 (1 step)
fast = 5 (2 steps)
Move 3: slow = 4 (1 step)
fast = 2 (2 steps: 5->2 wrapped around)
Move 4: slow = 5 (1 step)
fast = 4 (2 steps: 2->3->4)
Move 5: slow = 2 (1 step, wrapped to cycle)
fast = 2 (2 steps: 4->5->2)
They meet at node 2! But is this the cycle start?
Let's check...
Actually, the meeting point is NOT always the cycle start!
They might meet anywhere in the cycle!
THE QUESTION: How do we find the cycle START?
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Key observation after they meet:
- They met somewhere in the cycle
- Slow traveled some distance to get there
- Fast traveled twice that distance
This creates a special relationship!
The INSIGHT:
The distance from HEAD to CYCLE START
EQUALS
The distance from MEETING POINT to CYCLE START
Why? Let me show you visually...
VISUAL PROOF with our example:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
List: 1 -> 2 -> 3 -> 4 -> 5
โ โ
โโโโโโโโโโโโโโโโ
Let's say they meet at node 4 (different from before).
Count the distances:
HEAD(1) to CYCLE START(2): 1 step
CYCLE START(2) to MEETING(4): 2 steps
Cycle length: 4 nodes (2,3,4,5)
When slow reached the meeting point(4):
Slow traveled: 1 (to reach cycle) + 2 (in cycle) = 3 steps
When fast reached the meeting point(4):
Fast traveled: 2 ร 3 = 6 steps
Where did fast go?
1 -> 2 (1 step, entered cycle)
2 -> 3 -> 4 -> 5 -> 2 (4 more steps, one complete cycle)
2 -> 3 -> 4 (2 more steps)
Total: 1 + 4 + 2 = 7? Wait, that's wrong!
Let me recalculate correctly:
Fast moves 2 steps at a time
After 3 iterations:
Fast at: 1 -> 3 -> 5 -> 2 (wraps) -> 4 (wraps) -> ...
Actually, let's use the formula instead of tracing!
THE FORMULA (don't worry if you don't get it at first!)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
When they meet:
Slow traveled: L + k steps
Fast traveled: L + k + nC steps (went extra cycles)
L = distance from head to cycle start
k = distance from cycle start to meeting
C = cycle length
n = number of extra complete cycles fast made
Since Fast = 2 ร Slow:
L + k + nC = 2(L + k)
L + k + nC = 2L + 2k
nC = L + k
L = nC - k
What does this mean in English?
L = nC - k
L = (n-1)C + (C - k)
C - k = distance from meeting to cycle start!
So: Distance from head to cycle start
= Some complete cycles + distance from meeting to cycle start
This means:
Starting from head: walk L steps โ reach cycle start
Starting from meeting: walk L steps โ reach cycle start
(includes going around cycles)
Both travel the SAME distance L to reach cycle start!
PHASE 2: The Algorithm (Super Simple!)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
After Phase 1, we have:
- slow and fast both at meeting point
Phase 2:
1. Reset slow pointer to HEAD
2. Keep fast pointer at MEETING POINT
3. Move BOTH at the SAME SPEED (1 step at a time)
4. When they meet again โ That's the CYCLE START!
Why does this work?
Because both are now exactly L steps away from cycle start!
Moving at same speed โ they meet at cycle start! โ
Visual:
HEAD โโโโโโโโL stepsโโโโโโโ> CYCLE START
MEETING โโโโL stepsโโโโโโโโ> CYCLE START
(going around cycle)
They walk the same distance!
They meet at the same place!
That place is CYCLE START! โ
CONCRETE EXAMPLE (Final!)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
List: A -> B -> C -> D -> E
โ โ
โโโโโโโโโโโโโโโโ
Phase 1: They meet at D.
Distances:
HEAD(A) to CYCLE START(B): 1 step โ L = 1
CYCLE START(B) to MEETING(D): 2 steps โ k = 2
Cycle: B,C,D,E โ C = 4
Check formula: L = nC - k
1 = 4ร1 - 2? No, 4-2=2, not 1!
1 = 4ร0 - 2? No, -2, not 1!
Hmm, let me recalculate where they actually meet...
Actually, let's trace correctly:
slow: A(0) -> B(1) -> C(2) -> D(3) -> E(4) -> B(5) -> C(6)
fast: A(0) -> C(2) -> E(4) -> C(6) -> E(8) -> C(10)
Hmm, they don't meet at same iteration...
slow: position 0,1,2,3,4,5,6...
fast: position 0,2,4,6,8,10...
When do positions align in the cycle?
Slow at B(pos 5 overall, pos 1 in cycle)
Fast at B(pos 8 overall, pos 1 in cycle) ... different times!
Let me think differently...
Actually, this is getting complex. The KEY POINT is:
The formula GUARANTEES they meet at cycle start in Phase 2.
You don't need to trace it manually!
Trust the math! โ
๐จ Visual Understanding
List: 1 -> 2 -> 3 -> 4 -> 5 -> 6
โ โ
โโโโโโโโโโโโโโโโโโโโโ
L = 1 (head to node 2)
C = 5 (cycle length: 2,3,4,5,6)
Let's trace:
Initial:
slow = 1, fast = 1
Step 1:
slow = 2, fast = 3
Step 2:
slow = 3, fast = 5
Step 3:
slow = 4, fast = 2 (wrapped: 5->6->2)
Step 4:
slow = 5, fast = 4 (wrapped: 2->3->4)
Step 5:
slow = 6, fast = 6 (wrapped: 4->5->6)
They meet at node 6!
Now verify L = nC - k:
Meeting point: node 6
k = distance from cycle start (2) to meeting (6) = 4
L = 1
C = 5
Check: L = nC - k
1 = nร5 - 4
1 = 5 - 4 (n=1) โ
Phase 2: Find cycle start
slow = head (node 1)
fast = meeting point (node 6)
Move both 1 step:
slow = 2
fast = 2 (6 -> 2 in cycle)
They meet at node 2 = CYCLE START! โ
Distance from head to 2: 1 step
Distance from 6 to 2: 1 step (in cycle)
Equal! This proves L = nC - k โ
Visual Trace - Complete Algorithm
List: 3 -> 2 -> 0 -> -4
โ โ
โโโโโโโโโโโโ
PHASE 1: Detect Cycle
Initial:
slow = 3, fast = 3
Step 1:
slow = 2, fast = 0
Step 2:
slow = 0, fast = 2 (wrapped: -4 -> 2)
Step 3:
slow = -4, fast = -4 (wrapped: 0 -> -4)
They meet at -4! Cycle detected โ
PHASE 2: Find Cycle Start
Reset slow to head:
slow = 3 (head)
fast = -4 (meeting point)
Move both at SAME SPEED:
Step 1:
slow = 2
fast = 2 (from -4 -> 2 in cycle)
They meet at 2!
Return node 2 = CYCLE START โ
๐ฏ Approach 1: Hash Set (Brute Force)
The Most Natural Thinking ๐ญ
Core Logic:
Track visited nodes in a HashSet
First revisited node = cycle start!
Implementation
/**
* Using HashSet to find cycle start
* Time: O(n), Space: O(n)
*/
public ListNode detectCycle(ListNode head) {
Set<ListNode> visited = new HashSet<>();
ListNode current = head;
while (current != null) {
// Have we seen this node before?
if (visited.contains(current)) {
return current; // This is cycle start!
}
visited.add(current);
current = current.next;
}
return null; // No cycle
}
โฐ Time: O(n) - Visit each node once
๐พ Space: O(n) - Store all nodes in HashSet
โ Problem: Uses O(n) space! Not optimal for follow-up!
๐ฏ Approach 2: Floyd's Cycle Detection - Phase 2 (Optimal) โญ
Better Approach ๐ก
๐ง The Core Insight
Two-phase algorithm:
Phase 1: Detect cycle (fast & slow meet)
Phase 2: Find cycle start
- Reset slow to head
- Keep fast at meeting point
- Move both at SAME speed
- They meet at cycle start!
Mathematical proof: L = nC - k
The Strategy:
Floyd's Algorithm Extended:
Phase 1: Detect cycle
1. slow and fast start at head
2. Move slow 1 step, fast 2 steps
3. If they meet โ cycle exists
4. If fast reaches null โ no cycle
Phase 2: Find cycle start
5. Reset slow to head
6. Keep fast at meeting point
7. Move BOTH at SAME speed (1 step each)
8. They meet at cycle start!
Time: O(n), Space: O(1) โ
Implementation
/**
* Floyd's Cycle Detection - Complete Algorithm
* Time: O(n), Space: O(1)
*/
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
// PHASE 1: Detect cycle
ListNode slow = head;
ListNode fast = head;
// Find meeting point
while (fast != null && fast.next != null) {
slow = slow.next; // 1 step
fast = fast.next.next; // 2 steps
if (slow == fast) {
// Cycle detected! Break to phase 2
break;
}
}
// Check if no cycle found
if (fast == null || fast.next == null) {
return null; // No cycle
}
// PHASE 2: Find cycle start
// Reset slow to head, keep fast at meeting point
slow = head;
// Move both at SAME speed (1 step each)
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
// They meet at cycle start!
return slow; // or fast, they're equal
}
โฐ Time: O(n) - Two passes through list (at most)
๐พ Space: O(1) - Only two pointers
๐ Dry Run
Example 1: [3,2,0,-4], pos = 1
Goal: Find cycle start (node 2)
List: 3 -> 2 -> 0 -> -4
โ โ
โโโโโโโโโโโโ
PHASE 1: Detect Cycle
Initial:
slow = 3
fast = 3
Iteration 1:
slow = 2
fast = 0
slow != fast, continue
Iteration 2:
slow = 0
fast = 2 (from -4, wrapped to 2)
slow != fast, continue
Iteration 3:
slow = -4
fast = -4 (from 0 -> -4)
slow == fast! Cycle detected โ
Meeting point: -4
Break from loop
Check: fast == null? No
fast.next == null? No
Continue to Phase 2 โ
PHASE 2: Find Cycle Start
Reset slow to head:
slow = 3 (head)
fast = -4 (meeting point)
Move both at SAME speed:
Iteration 1:
slow = 2
fast = 2 (from -4 -> 2)
slow == fast! Loop ends
Return slow (node 2) โ
Verification:
L = 1 (head to cycle start)
k = 2 (cycle start to meeting point)
C = 3 (cycle length)
L = nC - k
1 = 3 - 2 โ (n=1)
Example 2: [1,2], pos = 0
Goal: Find cycle start (node 1, the head)
List: 1 -> 2
โ โ
โโโโโโ
PHASE 1: Detect Cycle
Initial:
slow = 1, fast = 1
Iteration 1:
slow = 2
fast = 2 (1 -> 2 -> 1 -> 2)
slow == fast! Meeting at 2
Break
PHASE 2: Find Cycle Start
Reset slow:
slow = 1 (head)
fast = 2 (meeting)
Move both:
Iteration 1:
slow = 2
fast = 1 (2 -> 1)
Continue
Iteration 2:
slow = 1
fast = 2
Continue
Wait, this seems wrong! Let me recalculate...
Actually, when they meet at 2:
slow = 1 (head)
fast = 2 (meeting)
Move once:
slow = 2
fast = 1 (from 2 -> 1 in cycle)
Move again:
slow = 1 (from 2 -> 1)
fast = 2 (from 1 -> 2)
Hmm, they keep alternating!
Actually, for cycle at head:
L = 0 (head IS cycle start)
When L = 0:
slow at head = cycle start already!
fast at meeting point
Move slow 0 steps, they should meet immediately...
Let me retrace Phase 1:
Initial: slow = 1, fast = 1
Step 1: slow = 2, fast = 1 (1->2->1)
Wait! fast = fast.next.next = 1.next.next
From 1: next = 2, next.next = 1
So fast = 1
slow = 2, fast = 1, not equal
Step 2: slow = 1, fast = 2
Continue...
Step 3: slow = 2, fast = 1
They alternate! They'll meet when slow catches up.
Actually, they DO meet - both will be at same position
eventually in the cycle.
Let me trace more carefully:
slow moves 1 at a time: 1->2->1->2->1...
fast moves 2 at a time: 1->1->1->1... (stays at 1!)
Wait, fast.next.next from 1:
1.next = 2
2.next = 1
So fast stays at 1 every other turn? No...
Let me be more careful:
Iteration 1:
slow = head.next = 2
fast = head.next.next = 1
Iteration 2:
slow = 2.next = 1
fast = 1.next.next = 1
slow = 1, fast = 1
They meet at 1! โ
PHASE 2:
slow = head = 1
fast = meeting = 1
Already equal! Return 1 โ
Example 3: [1], pos = -1
Goal: No cycle
List: 1 -> null
PHASE 1:
Initial: slow = 1, fast = 1
Check: fast != null? Yes
fast.next != null? No!
Loop doesn't execute
Check: fast.next == null? Yes
Return null โ
๐ฏ Why This Works - Deep Dive
The Mathematical Foundation:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Define:
L = distance from head to cycle start
C = cycle length
k = distance from cycle start to meeting point
When they meet (Phase 1):
Slow has traveled: L + k
- L steps to reach cycle
- k steps into cycle
Fast has traveled: L + k + nC
- Same L + k
- Plus n complete cycles (n โฅ 1)
Fast speed = 2 ร Slow speed:
Distance_fast = 2 ร Distance_slow
L + k + nC = 2(L + k)
L + k + nC = 2L + 2k
nC = L + k
L = nC - k โ THE KEY EQUATION!
What does L = nC - k mean geometrically?
nC = n complete cycles around
nC - k = n cycles minus k steps
= going backwards k steps from cycle start
= distance from meeting point to cycle start
(going forward)
Visual:
Cycle start โโโโโkโโโโโ Meeting point
โโโโnC-kโโโโ
So L (from head to start) equals
(nC - k) (from meeting to start going forward)!
Why Phase 2 Works:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
After Phase 1, we have:
- slow and fast at meeting point
- Meeting point is k steps from cycle start
In Phase 2:
- Reset slow to head (L steps from cycle start)
- Keep fast at meeting point (nC-k steps from cycle start)
Since L = nC - k:
Both are EQUAL distance from cycle start!
Moving both at same speed:
After L steps:
- slow reaches cycle start (from head)
- fast reaches cycle start (from meeting point)
They meet at cycle start! โ
Example Verification:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
List: A -> B -> C -> D -> E
โ โ
โโโโโโโโโโโโโโโโ
L = 1 (A to B)
C = 4 (B, C, D, E)
Trace Phase 1:
slow: A -> B -> C -> D -> E -> B -> C
fast: A -> C -> E -> C -> E -> C -> E
They meet at... let's calculate:
After 3 slow steps (at D):
slow at D (k=2)
After 6 fast steps (at D):
fast at D
They meet at D!
k = 2 (B to D)
Verify: L = nC - k
1 = nร4 - 2
1 = 4 - 2 (n=1) โ
1 = 2? No! Let me recalculate...
Actually, when they meet:
slow has traveled: L + k = 1 + k
fast has traveled: 2(L + k) = 2 + 2k
fast = slow + nC
2 + 2k = 1 + k + nC
1 + k = nC
If they meet at D (k=2):
1 + 2 = nC
3 = nC
n = 3/4? Not integer!
Let me trace more carefully with positions:
slow: 0->1->2->3->4->1->2...
fast: 0->2->4->2->4->2...
slow at 4, fast at 4 after 4 slow moves โ
k = 3 (from 1 to 4)
L = nC - k
1 = 4n - 3
4 = 4n
n = 1 โ
Phase 2:
slow = 0 (head)
fast = 4 (meeting)
Step 1:
slow = 1
fast = 1 (4->1 in cycle)
Meet at 1 = cycle start! โ
Time Complexity:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Phase 1: O(n)
slow travels at most L + C steps
(reaches cycle, travels once around)
Phase 2: O(n)
Both travel at most L steps
L โค n
Total: O(n) + O(n) = O(n) โ
Space: O(1) - Only two pointers
Why Equal Speed in Phase 2?
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Critical: In Phase 2, BOTH move at SAME speed!
If fast continued at 2x speed:
They wouldn't meet at cycle start!
fast would overshoot!
By moving at same speed:
The equal distances (L = nC - k) are preserved
They travel together and meet precisely at start โ
Alternative Explanation (Intuitive)
Think of it as a race:
Phase 1: Fast and slow meet in the cycle
They're somewhere in the cycle, not at start
Phase 2: Find the start
Reset slow to head (outside cycle)
Keep fast inside cycle at meeting point
The trick: The distance from head to cycle start
equals the distance from meeting to cycle start!
So if both move at SAME speed:
When slow enters the cycle (at start)
Fast also reaches the start (from meeting point)
They meet! โ
Why do the distances equal?
Mathematical proof: L = nC - k
The meeting point is positioned such that
going back to start takes same distance as
entering from head!
โ ๏ธ Common Mistakes to Avoid
Mistake 1: Not breaking after detecting cycle
// โ WRONG - Doesn't break, keeps looping
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
// Need to break here!
}
}
// Phase 2 code here...
// โ CORRECT - Break to proceed to Phase 2
if (slow == fast) {
break; // Exit to Phase 2
}
Mistake 2: Moving fast at 2x speed in Phase 2
// โ WRONG - Phase 2 uses different speeds
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next.next; // WRONG! Should be .next
}
// โ CORRECT - Both move at SAME speed
while (slow != fast) {
slow = slow.next;
fast = fast.next; // Same speed!
}
Mistake 3: Not checking for no cycle
// โ WRONG - Assumes cycle exists
while (fast != null && fast.next != null) {
// ...
}
// Directly go to Phase 2 without checking
// โ CORRECT - Check if cycle exists
if (fast == null || fast.next == null) {
return null; // No cycle!
}
Mistake 4: Not resetting slow to head
// โ WRONG - Doesn't reset slow
if (slow == fast) {
break;
}
// slow is still at meeting point!
while (slow != fast) {
// ...
}
// โ CORRECT - Reset slow to head
if (slow == fast) {
break;
}
slow = head; // Reset!
while (slow != fast) {
// ...
}
Mistake 5: Returning meeting point instead of cycle start
// โ WRONG - Returns meeting point
if (slow == fast) {
return slow; // This is meeting, not cycle start!
}
// โ CORRECT - Continue to Phase 2
if (slow == fast) {
break;
}
// Phase 2 to find cycle start
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow; // Cycle start!
๐ฏ Pattern Recognition
Problem Type: Find Cycle Start in Linked List
Core Pattern: Floyd's Cycle Detection - Extended
When to Apply:
โ Find where cycle begins
โ Not just detect cycle
โ Need O(1) space
โ Can't modify list
โ Two-phase algorithm
Recognition Keywords:
- "Where cycle begins"
- "Cycle start node"
- "First node of cycle"
- "Entry point of cycle"
- "Without extra space"
Similar Problems:
- Linked List Cycle (LC 141) - Phase 1 only
- Happy Number (LC 202) - Implicit cycle
- Find Duplicate Number (LC 287) - Array as list
Key Components:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Phase 1: Detect cycle (slow == fast) โ
โ Phase 2: Find start (reset, same speed) โ
โ Mathematical: L = nC - k โ
โ Time: O(n), Space: O(1) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
This is Floyd's algorithm EXTENDED!
๐ง Interview Strategy
Step 1: "Two phases: detect cycle, find start"
Step 2: "Phase 1: fast & slow meet in cycle"
Step 3: "Phase 2: reset slow, both move same speed"
Step 4: "Mathematical proof: L = nC - k"
Step 5: "O(n) time, O(1) space"
Key Points to Mention:
- Two-phase Floyd's algorithm
- Phase 1: Detect cycle (2x and 1x speed)
- Phase 2: Find start (both same speed!)
- Reset slow to head after detection
- Mathematical insight: L = nC - k
- Equal distances from head and meeting point
- Time: O(n), Space: O(1)
- Alternative: HashSet O(n) space
Why This Approach?
"I'll use Floyd's cycle detection algorithm with two phases.
First, I detect if a cycle exists using fast and slow pointers
with 2x and 1x speeds. If they meet, a cycle exists. Then comes
the key insight: I reset the slow pointer to the head and keep
fast at the meeting point. Now I move BOTH at the SAME speed.
Due to the mathematical relationship L = nC - k, they will meet
exactly at the cycle start. This gives O(n) time with O(1) space."
Why Phase 2 Works? (Mathematical Proof)
"When fast and slow meet, slow has traveled L + k distance and
fast has traveled 2(L + k) distance. Since fast is also L + k + nC,
we get L = nC - k. This means the distance from head to cycle
start (L) equals the distance from meeting point to cycle start
(nC - k). So by moving both at the same speed, one from head and
one from meeting point, they'll both reach the cycle start at the
same time."
Why Same Speed in Phase 2?
"In Phase 2, we move both pointers at the same speed, not
different speeds like Phase 1. This is critical because we're
leveraging the equal distances property from our mathematical
proof. If we used different speeds, they wouldn't meet at the
cycle start."
Edge Cases to Mention:
โ No cycle (return null)
โ Cycle at head (L = 0)
โ Single node with self-loop
โ Two nodes with cycle
โ All nodes in cycle
๐ Quick Revision Notes
๐ฏ Core Concept:
Find Cycle Start: Use Floyd's 2-phase algorithm! Phase 1: Detect cycle (fast 2x, slow 1x). Meet โ cycle exists. Phase 2: Reset slow to head, fast at meeting. Move both at SAME speed (1x). Meet at cycle start! Math: L = nC - k. O(n) time, O(1) space!
โก Quick Implementation:
import java.util.HashSet;
class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
class Test {
public ListNode detectCycle(ListNode head) {
// // Approach 1 - simple visited hashset
// HashSet<ListNode> visited = new HashSet<>();
// ListNode curr = head;
// while (curr != null) {
// if(visited.contains(curr)) {
// return curr;
// }
// visited.add(curr);
// curr = curr.next;
// }
// return null;
// Approach 2 - using fast and slow pointers
ListNode slow = head;
ListNode fast = head;
boolean isCycle = false;
// phase 1 - let slow and fast meet
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(slow == fast) {
isCycle = true;
slow = head;
break;
}
}
// phase 2 - if cycle found
if(isCycle) {
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
return null;
}
public static void main(String[] args) {
Test t = new Test();
ListNode head1 = new ListNode(3); // 3,2,0,-4 (-4 -> 2 is a loop)
head1.next = new ListNode(2);
head1.next.next = new ListNode(0);
head1.next.next.next = head1.next;
System.out.println("head1: "+t.detectCycle(head1).val); // 2
System.out.println("head2: "+t.detectCycle(null)); // empty list // null
System.out.println("head3: "+t.detectCycle(new ListNode(1))); // single element // null
ListNode head4 = new ListNode(1); // 1 - self loop to itself
head4.next = head4;
System.out.println("head4: "+t.detectCycle(head4).val); // 1
ListNode head5 = new ListNode(3); // 3,2 (no loop)
head5.next = new ListNode(2);
System.out.println("head5: "+t.detectCycle(head5)); // null
ListNode head6 = new ListNode(3); // 3,2,0,-4 (-4 -> 3 is a loop)
head6.next = new ListNode(2);
head6.next.next = new ListNode(0);
head6.next.next.next = new ListNode(-4);
head6.next.next.next.next = head6;
System.out.println("head6: "+t.detectCycle(head6).val); // 3
ListNode head7 = new ListNode(3); // 3,2,0,-4 (-4 -> 0 is a loop)
head7.next = new ListNode(2);
head7.next.next = new ListNode(0);
head7.next.next.next = new ListNode(-4);
head7.next.next.next.next = head7.next.next.next;
System.out.println("head7: "+t.detectCycle(head7).val); // -4
}
}
๐ Key Insights:
- Pattern: Floyd's 2-Phase Algorithm
- Phase 1: Detect cycle (2x vs 1x speed)
- Phase 2: Find start (1x vs 1x speed!)
- Critical: Reset slow to head after detection
- Speed: Both SAME in Phase 2 (not 2x!)
- Math: L = nC - k (KEY equation!)
- Meaning: Distance from head = distance from meeting
- Result: Meet at cycle start
- Time: O(n), Space: O(1)
๐ช Memory Aid:
"Phase 1: Detect! Phase 2: Reset slow, same speed, meet at start!"
Think: "L = nC - k: equal distances, equal meeting!" ๐งฎ
๐ก The Key Insight:
Mathematical Magic: L = nC - k
L = head to cycle start
nC - k = meeting to cycle start (forward)
Equal distances!
Both at same speed โ meet at start! โ
โ ๏ธ Critical Details:
1. Phase 1: Fast 2x, slow 1x
2. If meet: break (cycle exists)
3. If no meet: return null
4. Phase 2: Reset slow = head
5. Keep fast at meeting point
6. CRITICAL: Both SAME speed (not 2x!)
7. Move: slow.next and fast.next
8. Meet: Return slow (cycle start)
9. Math: L = nC - k explains why it works
๐ฅ Why Same Speed in Phase 2:
Phase 1: Different speeds (2x vs 1x)
Purpose: Detect cycle
Result: Meet in cycle
Phase 2: SAME speed (1x vs 1x)
Purpose: Find start
Why same? L = nC - k (equal distances)
If different: Would overshoot!
Same speed preserves the distance equality!
๐ก Visual Summary:
Phase 1: Detect
S F
โ โ
1 โ 2 โ 3 โ 4 โ 5
โ โ
โโโโโโโโโโโโโ
Move: S 1x, F 2x
Meet in cycle โ
Phase 2: Find Start
S (reset to head)
โ
1 โ 2 โ 3 โ 4 โ 5
โ F โ
โโโโโโโโโโโโโ
Move: Both 1x
Meet at 2 (start) โ
๐งฎ The Mathematical Proof:
When they meet:
Slow: L + k
Fast: 2(L + k) = L + k + nC
Solve:
L + k + nC = 2L + 2k
nC = L + k
L = nC - k โ
What it means:
Head to start: L
Meeting to start: nC - k
L = nC - k means equal distances!
Same speed โ meet at start! โ
๐งช Edge Cases
Case 1: No cycle
Input: head = [1,2,3], pos = -1
Output: null
(Fast reaches null in Phase 1)
Case 2: Cycle at head
Input: head = [1,2], pos = 0
Output: node 1
(L = 0, immediately at cycle start)
Case 3: Single node, self-loop
Input: head = [1], pos = 0
Output: node 1
(Cycle starts at only node)
Case 4: All nodes in cycle
Input: head = [1,2,3], pos = 0
Output: node 1
(Entire list is cycle)
Case 5: Cycle in middle
Input: head = [1,2,3,4,5], pos = 2
Output: node 3
(Standard case)
All handled correctly! โ
Related Patterns
- Linked List Cycle (LC 141) - Phase 1 only
- Find Duplicate Number (LC 287) - Same algorithm on array
- Happy Number (LC 202) - Implicit cycle detection
Happy practicing! ๐ฏ
Note: This is one of the most elegant algorithms in computer science! The mathematical proof (L = nC - k) is beautiful and explains why the two-phase approach works perfectly! This is a MUST-KNOW for interviews! ๐งฎโจ