name: Fast & Slow Pointers slug: fast-slow-pointers difficulty_level: 2 description: > Use two pointers moving at different speeds to detect cycles, find midpoints, or identify patterns in sequences. The fast pointer advances twice as quickly, allowing detection of structural properties without extra space. when_to_use: | - Detecting cycles in linked lists or sequences - Finding the middle of a linked list - Finding the start of a cycle - Happy number problem - Palindrome linked list verification metaphor: | Imagine two runners on a circular track. If one runs twice as fast as the other, the fast runner will eventually lap the slow runner—they'll meet at some point on the track. This proves the track is circular (has a cycle). Another analogy: finding the middle of a line of people. Have two people start at the front—one takes one step at a time, the other takes two. When the fast person reaches the end, the slow person is at the middle. core_concept: | The **fast & slow pointers** technique (also called Floyd's cycle detection or "tortoise and hare") uses two pointers moving at different speeds: - **Slow pointer**: Moves 1 step at a time - **Fast pointer**: Moves 2 steps at a time Key insights: 1. **Cycle detection**: In a cyclic structure, fast will eventually catch up to slow (they'll meet inside the cycle). In a non-cyclic structure, fast will reach the end. 2. **Finding middle**: When fast reaches the end, slow is at the middle (fast traveled 2x the distance). 3. **Finding cycle start**: After detecting a cycle, reset one pointer to start. Move both at the same speed—they meet at the cycle start. (Mathematical proof: the distances work out perfectly.) visualization: | **Cycle Detection:** ``` List: 1 → 2 → 3 → 4 → 5 ↑ ↓ 7 ← 6 Step 1: slow=1, fast=1 Step 2: slow=2, fast=3 Step 3: slow=3, fast=5 Step 4: slow=4, fast=7 Step 5: slow=5, fast=4 Step 6: slow=6, fast=6 ← They meet! Cycle exists. ``` **Finding Middle:** ``` List: 1 → 2 → 3 → 4 → 5 → null Step 1: slow=1, fast=1 Step 2: slow=2, fast=3 Step 3: slow=3, fast=5 Step 4: fast reaches null slow is at middle (3) ``` **Finding Cycle Start:** ``` After detecting cycle at node X: 1. Reset slow to head, keep fast at meeting point 2. Move both at same speed (1 step each) 3. They meet at cycle start Why? Math: Let's say: - Distance from head to cycle start = A - Distance from cycle start to meeting point = B - Cycle length = C At meeting: slow traveled A + B fast traveled A + B + nC (some complete cycles) Since fast travels 2x: 2(A + B) = A + B + nC Therefore: A + B = nC, so A = nC - B = (n-1)C + (C-B) This means: distance from head to cycle start = distance from meeting point to cycle start (going forward) ``` code_template: | class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def has_cycle(head: ListNode) -> bool: """Detect if linked list has a cycle.""" if not head or not head.next: return False slow = head fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False def find_cycle_start(head: ListNode) -> ListNode: """Find the node where the cycle begins.""" if not head or not head.next: return None # Phase 1: Detect cycle slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: break else: return None # No cycle # Phase 2: Find cycle start slow = head while slow != fast: slow = slow.next fast = fast.next return slow def find_middle(head: ListNode) -> ListNode: """Find the middle node of linked list.""" if not head: return None slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next return slow # Middle (or second middle if even length) def is_happy_number(n: int) -> bool: """Check if number is happy (sum of squared digits eventually = 1).""" def get_next(num: int) -> int: total = 0 while num > 0: digit = num % 10 total += digit * digit num //= 10 return total slow = n fast = get_next(n) while fast != 1 and slow != fast: slow = get_next(slow) fast = get_next(get_next(fast)) return fast == 1 def is_palindrome_linked_list(head: ListNode) -> bool: """Check if linked list is a palindrome.""" if not head or not head.next: return True # Find middle slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next # Reverse second half prev = None while slow: next_node = slow.next slow.next = prev prev = slow slow = next_node # Compare halves left, right = head, prev while right: if left.val != right.val: return False left = left.next right = right.next return True recognition_signals: - "linked list cycle" - "detect cycle" - "find middle" - "happy number" - "palindrome linked list" - "circular array" - "Floyd's" - "tortoise and hare" - "meeting point" - "cycle start" common_mistakes: - title: Not checking fast.next before advancing description: | Accessing `fast.next.next` without first checking `fast.next` causes null pointer errors when the list has even length. fix: | Always check both `fast` and `fast.next`: ```python while fast and fast.next: fast = fast.next.next ``` - title: Wrong initialization for cycle detection description: | Starting slow and fast at different positions (e.g., slow=head, fast=head.next) changes the math for finding the cycle start. fix: | Start both at head for consistency. The algorithms are designed assuming both start at the same position. - title: Forgetting to handle empty or single-node lists description: | Accessing head.next or head.next.next on empty or single-node lists causes errors. fix: | Add early returns: ```python if not head or not head.next: return False # or appropriate value ``` - title: Confusing meeting point with cycle start description: | Returning the meeting point instead of finding the actual cycle start gives the wrong answer. fix: | After detecting a cycle (meeting point), reset one pointer to head and advance both at the same speed to find the cycle start. variations: - name: Cycle detection description: | Determine if a linked list or sequence has a cycle. If fast catches slow, there's a cycle. example: "Linked List Cycle, Circular Array Loop" - name: Finding cycle start description: | After detecting a cycle, find the node where the cycle begins using the two-phase approach. example: "Linked List Cycle II" - name: Finding middle description: | When fast reaches the end, slow is at the middle. Useful for divide and conquer on linked lists. example: "Middle of Linked List, Sort List (merge sort needs middle)" - name: Happy number description: | Treat the sequence of digit-square sums as a linked list. Either reaches 1 (happy) or cycles (unhappy). example: "Happy Number" - name: Palindrome check description: | Find middle, reverse second half, compare. Combines finding middle with linked list reversal. example: "Palindrome Linked List" related_patterns: - two-pointers - linkedlist-reversal prerequisite_patterns: - two-pointers