Fast & Slow Pointers
Learn the fast and slow pointer technique for detecting cycles, finding midpoints, and more.
Fast & Slow Pointers
The fast and slow pointer technique uses two pointers moving through a linked list at different speeds. The slow pointer moves one step at a time. The fast pointer moves two steps at a time. This simple difference unlocks several powerful algorithms.
Also called Floyd's Cycle Detection Algorithm or the tortoise and hare algorithm.
Problem 1 โ detect a cycle
If a linked list has a cycle, the fast pointer will eventually lap the slow pointer and they will meet. If there is no cycle, the fast pointer reaches the end.
def has_cycle(head):
slow = head
fast = head
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 exists
return False # fast reached end โ no cycleWhy they always meet inside the cycle: Once both pointers are inside the cycle, fast gains 1 step on slow every iteration. If the cycle has length L, fast catches slow within L iterations.
Problem 2 โ find the midpoint
When fast reaches the end, slow is exactly at the middle.
def find_middle(head):
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow # slow is at the middle
# Example: 1 โ 2 โ 3 โ 4 โ 5
# After loop: slow = node(3) โ the middle
# Even length: 1 โ 2 โ 3 โ 4
# After loop: slow = node(3) โ second middle (standard choice)This is used in merge sort on linked lists โ find the middle, split in two, sort each half, merge.
Problem 3 โ find the start of a cycle
If a cycle exists, find exactly where it begins.
def find_cycle_start(head):
slow = head
fast = head
meeting_point = None
# phase 1 โ detect cycle
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
meeting_point = slow
break
if not meeting_point:
return None # no cycle
# phase 2 โ find cycle start
# move one pointer to head, keep other at meeting point
# both move at same speed โ they meet at cycle start
pointer1 = head
pointer2 = meeting_point
while pointer1 != pointer2:
pointer1 = pointer1.next
pointer2 = pointer2.next
return pointer1 # cycle startWhy this works: The math shows that the distance from head to cycle start equals the distance from the meeting point to cycle start โ moving both at equal speed, they meet exactly at the start.
Problem 4 โ check if linked list is a palindrome
def is_palindrome(head):
# step 1 โ find middle
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# step 2 โ reverse the second half
prev = None
while slow:
next_node = slow.next
slow.next = prev
prev = slow
slow = next_node
# step 3 โ compare both halves
left = head
right = prev
while right:
if left.value != right.value:
return False
left = left.next
right = right.next
return TrueProblem 5 โ find kth node from the end
Move fast pointer k steps ahead first, then move both at the same speed. When fast reaches the end, slow is at the kth node from the end.
def kth_from_end(head, k):
slow = head
fast = head
# move fast k steps ahead
for _ in range(k):
if not fast:
return None # k is larger than list length
fast = fast.next
# move both until fast reaches end
while fast:
slow = slow.next
fast = fast.next
return slow # kth node from endAll five problems โ same two pointers, different questions
| Problem | Fast speed | Slow speed | Key insight |
|---|---|---|---|
| Detect cycle | 2 steps | 1 step | They meet if cycle exists |
| Find midpoint | 2 steps | 1 step | When fast ends, slow is middle |
| Find cycle start | 2 steps then 1 | 1 step then 1 | Math: distances are equal |
| Palindrome check | 2 steps | 1 step | Find middle then compare |
| Kth from end | 1 step (offset k) | 1 step | Offset gap equals k |
The fast and slow pointer pattern is one of the most powerful linked list techniques. Recognize it whenever a problem involves cycles, midpoints, or relative positions within a linked list.
Complexity
| Problem | Time | Space |
|---|---|---|
| Detect cycle | O(n) | O(1) |
| Find midpoint | O(n) | O(1) |
| Find cycle start | O(n) | O(1) |
| Palindrome check | O(n) | O(1) |
| Kth from end | O(n) | O(1) |