Home › Blog › Fast and Slow Pointers

Fast and Slow Pointers Pattern (Floyd's Cycle Detection)

Detect cycles, find where they start and find the middle of a list in O(1) space, with tested Python code.

The fast and slow pointers pattern walks two pointers through the same sequence at different speeds (slow moves one step, fast moves two) so that they meet if there is a cycle, or so that slow stops at the middle when fast reaches the end. Reach for it when a problem gives you a linked list or a "next value" rule and asks about a cycle, where the cycle starts, or the middle element, especially when it wants O(1) extra space.

It is also called Floyd's cycle detection or the tortoise and hare algorithm. It is a special case of the two pointers pattern: both pointers move in the same direction, just at different speeds. This guide gives you the signals, a Python template, the short proof behind it, three worked LeetCode problems and a practice list. Every snippet below was run against test cases in Python before we published it.

When to use the fast and slow pointers pattern

Look for these signals in the problem statement:

If the problem is about pairs in a sorted array (two sum, 3Sum, container with most water), that is the opposite-ends version of two pointers instead. If it is about a contiguous range, see the sliding window pattern.

The Python template

Two functions cover most problems: one detects a cycle, the other finds the middle. Both use the same loop guard.

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def has_cycle(head):
    slow = fast = head
    while fast and fast.next:          # fast needs two valid steps
        slow = slow.next               # 1 step
        fast = fast.next.next          # 2 steps
        if slow is fast:               # compare nodes, not values
            return True
    return False

def middle_node(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow                        # second middle when the length is even

The guard while fast and fast.next is the whole safety net. If either is None, the list ended, so there is no cycle. That one line handles empty lists, single nodes and both odd and even lengths.

Why the fast and slow pointers meet (the short proof)

Interviewers often ask "why does this work?" after you code it. Here is the argument in plain terms.

  1. They must meet. Once both pointers are inside the cycle, fast gains exactly one node on slow every step. The gap shrinks by one each time, so it hits zero within one lap. Fast can never jump over slow.
  2. Where the cycle starts. Let a be the distance from the head to the cycle start, b the distance from the cycle start to the meeting point, and L the cycle length. Slow walked a + b; fast walked twice that. The extra distance fast covered is whole laps, so a + b = kL for some whole number k.
  3. Rearranged, a = kL - b. Walking a steps from the meeting point therefore lands exactly on the cycle start. So reset one pointer to the head, move both one step at a time, and they meet at the start.

That second phase is what turns "is there a cycle?" into "where does it begin?" without any extra memory.

Worked problems

1. Linked List Cycle II (LeetCode 142, Medium)

Problem: return the node where the cycle begins, or None if there is no cycle. The problem says not to modify the list and its follow-up asks for O(1) memory, which is exactly what Linked List Cycle II is testing.

Idea: phase 1 finds a meeting point inside the cycle. Phase 2 starts a new pointer at the head and moves it in lockstep with slow; by the proof above, they meet at the cycle start.

def detect_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow is fast:               # phase 1: they met inside the cycle
            ptr = head
            while ptr is not slow:     # phase 2: same distance to the start
                ptr = ptr.next
                slow = slow.next
            return ptr
    return None

Time: O(n). Space: O(1). If the cycle starts at the head (a = 0), phase 2 returns immediately, which is correct.

2. Happy Number (LeetCode 202, Easy)

Problem: repeatedly replace a number with the sum of the squares of its digits. Return true if it reaches 1, false if it loops forever.

Idea: there is no linked list, but the "next number" rule is a next pointer. Every sequence either reaches 1 (which maps to itself) or falls into a cycle that does not contain 1. Run slow with one step and fast with two; if fast reaches 1 the number is happy, and if they meet first it is not.

def is_happy(n):
    def step(x):
        total = 0
        while x:
            x, digit = divmod(x, 10)
            total += digit * digit
        return total

    slow, fast = n, step(n)
    while fast != 1 and slow != fast:
        slow = step(slow)
        fast = step(step(fast))
    return fast == 1

Time: O(log n) per step (the number of digits). For any input up to 10 digits, one step gives at most 10 × 81 = 810, so the sequence stays small and the loop is short. Space: O(1). A hash set of seen numbers also works and is fine to mention, but the two-pointer version is the answer to "can you do it without extra memory?"

3. Find the Duplicate Number (LeetCode 287, Medium)

Problem: nums has n + 1 integers, each in [1, n], and exactly one value repeats (possibly more than twice). You may not modify the array and may use only constant extra space.

Idea: treat index i as a node whose next pointer is nums[i]. Index 0 is never a target (values start at 1), so it is a safe head. Two indices point to the duplicate value, so the duplicate is the entrance of the cycle. Run the same two phases as Linked List Cycle II, on indices instead of nodes.

def find_duplicate(nums):
    slow = fast = nums[0]
    while True:                        # phase 1: meet inside the cycle
        slow = nums[slow]
        fast = nums[nums[fast]]
        if slow == fast:
            break
    slow = nums[0]                     # phase 2: walk to the cycle entrance
    while slow != fast:
        slow = nums[slow]
        fast = nums[fast]
    return slow

Time: O(n). Space: O(1), and the array is untouched. This is why the cyclic sort pattern (which swaps values into place) does not fit this problem even though the values are in [1, n].

Complexity of fast and slow pointer solutions

TaskTimeExtra spaceHash-set alternative
Detect a cycleO(n)O(1)O(n) time, O(n) space
Find the cycle startO(n)O(1)O(n) time, O(n) space
Find the middle nodeO(n), one passO(1)Count, then walk: two passes
Duplicate in [1, n] without modifyingO(n)O(1)Set uses O(n); sorting modifies or copies
Happy NumberO(log n) per stepO(1)Set of seen sums

Need a refresher on why O(n) beats O(n log n) at scale? Try the free Big-O complexity visualizer or the Big-O cheat sheet.

Common bugs and edge cases

Tip: Say the invariant out loud before you code: "fast moves two, slow moves one, so inside a cycle the gap closes by one each step." It shows the interviewer you know why the code is correct, not just what to type.

Practice list: 9 fast and slow pointer problems

Work through these in order. Difficulty labels are LeetCode's own, checked as of October 2026.

#ProblemDifficultyWhat it adds
141Linked List CycleEasyThe base template
876Middle of the Linked ListEasyMiddle-finding, second middle on even lengths
202Happy NumberEasyCycle in a number sequence, no list
234Palindrome Linked ListEasyFind the middle, reverse the second half, compare
142Linked List Cycle IIMediumPhase 2: the cycle start
2095Delete the Middle Node of a Linked ListMediumStop one node before the middle
143Reorder ListMediumMiddle + reversal + merge in one problem
287Find the Duplicate NumberMediumImplicit linked list over array indices
457Circular Array LoopMediumCycle detection with direction and length rules

Problems 234 and 143 also need list reversal; the in-place linked list reversal pattern covers that step. For where this pattern sits among the others, see 15 LeetCode patterns for interviews and the coding interview cheat sheet.

How to practice explaining it

Knowing the template is half the job. In a real round you also have to explain the proof, name the edge cases and state the complexity while someone listens. Practice that out loud: solve one problem from the list, then explain it in under two minutes without looking at your code.

CoPilot Interview's Mock Interview can run a coding round built from your résumé and the job description, read each question aloud and score your spoken answer out of 10 with what to fix and a model answer. If you would rather not install anything, the browser AI mock interview has 113 real questions across 9 tracks, including coding.

Practice explaining Floyd's cycle detection out loud

Run a free AI mock interview in your browser, answer a coding question out loud, and get feedback on how clearly you explained it.

Try a free AI mock interview

FAQ

What is the fast and slow pointers pattern?

It is a technique where two pointers move through the same sequence at different speeds, usually one step and two steps. If the sequence has a cycle they meet inside it; if it does not, the fast pointer reaches the end while the slow pointer sits at the middle. It is also called Floyd's cycle detection or the tortoise and hare algorithm.

Why does the fast pointer move exactly two steps?

With speeds of one and two, the gap inside a cycle shrinks by exactly one node per step, so fast can never skip over slow and they must meet within one lap. Other speeds can work for detection, but one and two keep the code and the cycle-start proof simple.

How do you find where the cycle starts?

After the pointers meet, move one pointer back to the head and advance both one step at a time. The distance from the head to the cycle start equals the distance from the meeting point to the cycle start (modulo the cycle length), so they meet exactly at the start.

What is the time and space complexity of Floyd's cycle detection?

O(n) time and O(1) extra space. Slow enters the cycle within n steps, and the pointers meet within one more lap. The hash-set alternative is also O(n) time but uses O(n) space.

Is fast and slow pointers the same as two pointers?

It is a variant of two pointers. Classic two pointers usually start at opposite ends of a sorted array and move toward each other; fast and slow pointers start together and move in the same direction at different speeds.

Which LeetCode problems use fast and slow pointers?

The core set is Linked List Cycle (141), Linked List Cycle II (142), Middle of the Linked List (876), Happy Number (202), Find the Duplicate Number (287), Palindrome Linked List (234), Reorder List (143) and Circular Array Loop (457).