๐ข๐ Cycle Detection - Floyd's Algorithm
Imagine a linked list where the last node points back to an earlier node instead of null - creating an infinite loop! Floyd's Tortoise and Hare algorithm detects this in O(n) time with O(1) space. This elegant solution appears frequently at Google, Amazon, Microsoft, and Facebook!
๐ฏ Interview Alert!
Floyd's algorithm is a MUST-KNOW:
- โ Google - Common question
- โ Amazon - Frequently asked
- โ Microsoft - Standard interview
- โ Facebook - Regular appearance
- โ LinkedIn - Popular question
The O(1) space solution is what separates good from great!
The Problem
Detect if a linked list has a cycle
Example WITH cycle:
1 โ 2 โ 3 โ 4 โ 5
โ โ
โโโโโโโโโโโโโ
Cycle exists! Node 5 points back to node 3
Example WITHOUT cycle:
1 โ 2 โ 3 โ 4 โ 5 โ null
No cycle - ends with null
Challenge: Detect cycle in O(1) space (no HashSet!)
Floyd's Tortoise and Hare ๐ข๐
The brilliant insight: Use two pointers moving at different speeds!
The Algorithm
def has_cycle(head):
slow = head # ๐ข Tortoise - moves 1 step
fast = head # ๐ Hare - moves 2 steps
while fast and fast.next:
slow = slow.next # Move 1 step
fast = fast.next.next # Move 2 steps
if slow == fast:
return True # They met - cycle!
return False # Hare reached end - no cycle
That's it! Just 9 lines to detect cycles.
See It in Action
Watch the tortoise and hare move through the list:
Why It Works
๐ก The Race Track Analogy
Think of a circular race track:
- ๐ข Tortoise runs at 1 mph
- ๐ Hare runs at 2 mph (twice as fast!)
- If the track is circular, the hare will eventually lap the tortoise
- They MUST meet at some point!
Same with linked lists: If there's a cycle, fast will catch slow!
Step-by-Step Example
Let's trace through a list with a cycle:
List structure:
1 โ 2 โ 3 โ 4 โ 5
โ โ
โโโโโโโโโโโโโ
Step 0: Both start at node 1
๐ข๐ at 1
Step 1: Slow moves to 2, Fast moves to 3
๐ข at 2, ๐ at 3
Step 2: Slow moves to 3, Fast moves to 5
๐ข at 3, ๐ at 5
Step 3: Slow moves to 4, Fast moves to 4 (via cycle!)
๐ข at 4, ๐ at 4 โ They met! Cycle detected!
Finding the Cycle Start
Once we know there's a cycle, where does it start?
The Magic Trick
def find_cycle_start(head):
# Step 1: Detect cycle and find meeting point
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
break # Found meeting point
else:
return None # No cycle
# Step 2: Find cycle start
slow = head # Move slow to head
while slow != fast:
slow = slow.next # Both move 1 step
fast = fast.next
return slow # This is the cycle start!
Why Does This Work?
๐ก The Mathematics
Let's define:
- x = distance from head to cycle start
- y = distance from cycle start to meeting point
- C = cycle length
When they meet:
- Slow traveled: x + y
- Fast traveled: x + y + nC (n complete cycles)
- Fast = 2 ร Slow (twice the distance)
Therefore:
x + y + nC = 2(x + y)
x + y + nC = 2x + 2y
nC = x + y
x = nC - y
This means: Distance from head to cycle start (x) equals distance from meeting point to cycle start (nC - y)!
So: If we move both pointers at same speed, they meet at cycle start!
The Complete Code
Click Run to execute your code
Complexity Analysis
| Operation | Time | Space | Notes |
|---|---|---|---|
| Detect cycle | O(n) โ | O(1) โโ | Floyd's algorithm |
| Find cycle start | O(n) โ | O(1) โโ | Two-phase approach |
| Get cycle length | O(n) โ | O(1) โโ | Count after detection |
| Remove cycle | O(n) โ | O(1) โโ | Find start, break link |
| Using HashSet | O(n) | O(n) | Not optimal! |
Common Mistakes
โ Mistake #1: Not Checking fast.next
# WRONG - crashes if fast.next is null!
while fast:
fast = fast.next.next # Crashes!
# RIGHT - check both fast and fast.next
while fast and fast.next:
fast = fast.next.next # Safe!
โ Mistake #2: Moving Both Same Speed
# WRONG - both move 1 step
slow = slow.next
fast = fast.next # They'll never meet!
# RIGHT - fast moves 2 steps
slow = slow.next
fast = fast.next.next # Twice as fast!
โ Mistake #3: Using Extra Space
# WRONG - uses O(n) space
visited = set()
while current:
if current in visited:
return True
visited.add(current)
# RIGHT - O(1) space with Floyd's
# (Use the algorithm above!)
Interview Variations
Common Follow-ups
- Detect if cycle exists โ (covered)
- Find where cycle starts โ (covered)
- Find length of cycle โ (covered)
- Remove the cycle โ (covered)
- Find intersection of two lists (similar technique!)
- Check if list is palindrome (uses slow/fast pointers)
Interview Tips
๐ก How to Ace This Question
- โ Explain the analogy: "Like a race track - faster runner laps slower"
- โ Draw it out: Visualize the cycle and pointer movements
- โ Mention O(1) space: This is the key advantage over HashSet!
- โ Handle edge cases: Empty list, single node, no cycle
- โ Explain the math: Show you understand WHY it works
- โ Know the variations: Finding start, length, removal
โ What Interviewers Want to See
- Understanding of two-pointer technique
- Ability to optimize space complexity
- Knowledge of mathematical reasoning
- Handling edge cases properly
- Clear communication of algorithm
Real-World Applications
Where Is This Used?
- Deadlock detection: Finding circular dependencies
- Memory leak detection: Circular references
- Graph algorithms: Detecting cycles in graphs
- Duplicate detection: Finding repeated sequences
- Infinite loop detection: Program analysis
Summary
Floyd's Tortoise and Hare
- Use two pointers: slow (1 step) and fast (2 steps)
- If cycle exists: They will meet inside the cycle
- If no cycle: Fast reaches null
- To find start: Move one to head, both move 1 step, meet at start
- O(n) time, O(1) space: Optimal solution!
Interview tip: This is a classic two-pointer problem. The key insight is using different speeds to detect cycles. Always explain the race track analogy - it shows deep understanding!
What's Next?
You've mastered cycle detection! Next: Two Pointer Techniques - finding middle, nth from end, and palindrome checking!
Enjoying these tutorials?