Pattern

Fast & Slow
Pointers

Detect cycles, find midpoints, and solve linked list problems using two pointers moving at different speeds.

Roadmap

  1. What Is This Pattern?
  2. When to Use It
  3. Use Case 1 — Cycle Detection
  4. Use Case 2 — Finding Cycle Start
  5. Use Case 3 — Finding Middle of List
  6. Template Code
  7. Common Problems
  8. Interactive Demo
  9. Complexity Analysis
  10. Key Takeaways
Step 01

What Is This Pattern?

The Fast & Slow Pointers technique (also known as Floyd's Tortoise and Hare) uses two pointers that traverse a sequence at different speeds. Typically, the slow pointer moves 1 step at a time, while the fast pointer moves 2 steps at a time.

The Tortoise and the Hare

slow 1
2
3
fast 4
5
6
Slow (1 step)
Fast (2 steps)
Meeting point

After 2 iterations: slow is at node 3 (moved 2), fast is at node 5 (moved 4). The fast pointer advances twice as quickly, which creates the mathematical properties we exploit.

💡

Core principle: If there is a cycle, the fast pointer will eventually "lap" the slow pointer and they will meet. If there is no cycle, the fast pointer hits the end first. This simple idea solves an entire family of problems in O(1) space.

Step 02

When to Use It

Reach for the fast & slow pointers pattern whenever you see these signals:

Recognition Signals

Cycle Detection
"Does this linked list have a cycle?" or "Does this sequence eventually repeat?"
Finding the Middle
"Find the middle node" -- when fast reaches end, slow is at middle.
Cycle Start Point
"Where does the cycle begin?" uses a two-phase approach after detection.
Sequence Loops
"Happy number" or "duplicate in array" -- any function that repeatedly applies a mapping.

The alternative is worse: Without this pattern, cycle detection requires a HashSet (O(n) space) to remember visited nodes. Fast & slow pointers achieve the same result in O(1) space.

Step 03

Use Case 1 — Cycle Detection

Consider a linked list where the last node points back to an earlier node, creating a cycle. We deploy two pointers: slow moves 1 step, fast moves 2 steps.

Why Must They Meet?

Once both pointers are inside the cycle, think of the gap between them. Each iteration, fast gains exactly 1 step on slow (2 - 1 = 1). So the gap shrinks by 1 every step. No matter how large the cycle, the gap eventually reaches 0 -- they meet.

Gap shrinks: 5 4 3 2 1 0 (meet!)

Visual: Cycle Detection in Action

List: 1 → 2 → 3 → 4 → 5 → 6 → back to 3 (cycle)

Slow (turtle)
Fast (rabbit)
// Cycle Detection
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
    slow = slow.next;           // 1 step
    fast = fast.next.next;      // 2 steps
    if (slow == fast)
        return true;            // cycle found!
}
return false;                   // fast hit null, no cycle
Step 04

Use Case 2 — Finding the Cycle Start

After detecting the cycle (slow and fast meet), we can find where the cycle begins with a beautiful trick: reset one pointer to the head, then move both at speed 1. They will meet at the cycle start.

The Mathematical Proof

Let's define the distances:

F = distance from head to cycle start
a = distance from cycle start to meeting point
C = cycle length

-- At meeting point:
slow traveled: F + a
fast traveled: F + a + k*C (k full laps)

-- Fast goes 2x slow's distance:
2(F + a) = F + a + k*C
F + a = k*C
F = k*C - a -- (F steps from meeting point lands at cycle start!)

This means: starting from the meeting point and walking F more steps lands exactly at the cycle start. And walking F steps from the head also lands at the cycle start. So they meet there!

Phase 2: Finding the Start

p1 (head) 1
2
3
4
p2 (meet) 5
6
Both move at speed 1 → meet at node 3 (cycle start)
// Find Cycle Start (Phase 1 + Phase 2)
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
    slow = slow.next;
    fast = fast.next.next;
    if (slow == fast) {
        // Phase 2: reset slow to head, both move at speed 1
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;     // speed 1 now!
        }
        return slow;              // cycle start
    }
}
return null;                     // no cycle
Step 05

Use Case 3 — Finding the Middle of a List

Since fast moves at 2x speed, when fast reaches the end of the list, slow is exactly at the middle. No need to count the length first!

Visual: Fast Reaches End, Slow is at Middle

List: 1 → 2 → 3 → 4 → 5 — watch both pointers advance.

START
slow fast 1
2
3
4
5
STEP 1
1
slow 2
fast 3
4
5
STEP 2 — fast.next.next == null, stop
1
2
MIDDLE 3
4
fast 5
🎯

Even-length lists: For a list with even number of nodes (e.g., 1→2→3→4), slow lands on the second middle node (node 3). If you need the first middle, check fast.next != null && fast.next.next != null instead.

// Find Middle of Linked List
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
    slow = slow.next;           // 1 step
    fast = fast.next.next;      // 2 steps
}
return slow;                    // middle node
Step 06

Template Code

Here are all three templates together, fully annotated. These are the building blocks for every fast & slow pointer problem.

1. Cycle Detection

public boolean hasCycle(ListNode head) {
    ListNode slow = head, fast = head;

    while (fast != null && fast.next != null) {
        slow = slow.next;            // tortoise: 1 step
        fast = fast.next.next;       // hare: 2 steps

        if (slow == fast)
            return true;             // they met = cycle exists
    }
    return false;                    // fast reached end = no cycle
}

2. Find Cycle Start

public ListNode detectCycle(ListNode head) {
    ListNode slow = head, fast = head;

    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;

        if (slow == fast) {          // Phase 1: detect cycle
            slow = head;             // Phase 2: reset to head
            while (slow != fast) {
                slow = slow.next;    // both move at speed 1
                fast = fast.next;
            }
            return slow;             // meeting point = cycle start
        }
    }
    return null;                     // no cycle
}

3. Find Middle

public ListNode middleNode(ListNode head) {
    ListNode slow = head, fast = head;

    while (fast != null && fast.next != null) {
        slow = slow.next;            // 1 step
        fast = fast.next.next;       // 2 steps
    }
    return slow;                     // when fast stops, slow = middle
}
📝

Notice the pattern: All three share the exact same loop structure. The only differences are (1) what happens when slow == fast, and (2) what we return. Master the loop skeleton once, then adapt the response.

Step 07

Common Problems

These LeetCode problems are solved cleanly using the fast & slow pointers pattern.

#141
Linked List Cycle
Easy
#142
Linked List Cycle II
Medium
#876
Middle of the Linked List
Easy
#202
Happy Number
Easy
#287
Find the Duplicate Number
Medium
#234
Palindrome Linked List
Medium
💡

#287 Find the Duplicate Number is a particularly clever application: treat the array indices as linked list nodes where nums[i] is the "next" pointer. A duplicate value means two nodes point to the same next -- creating a cycle. Apply Floyd's algorithm to find the duplicate without extra space!

Step 08

Interactive Demo

Watch the pointers move step by step through real linked lists.

Demo 1: Cycle Detection



Press "Step" or "Run All" to begin.

Demo 2: Find Middle of List


Press "Step" or "Run All" to begin.
Step 09

Complexity Analysis

Time
O(n)
Space
O(1)

Why O(n) Time?

Cycle detection: If there is no cycle, fast pointer traverses the list once = O(n). If there is a cycle, once both pointers enter the cycle, they meet within at most C steps (where C = cycle length). Since C ≤ n, total work is O(n).

Finding cycle start: Phase 1 is O(n). Phase 2 walks at most F steps (distance from head to cycle start), which is ≤ n. Total: O(n).

Finding middle: Fast pointer traverses the entire list once = O(n). Slow pointer does n/2 steps.

O(1) space is the real win. A HashSet-based cycle detection uses O(n) space to store visited nodes. Floyd's algorithm uses only two pointer variables, no matter how large the input. This is the hallmark of the pattern.

Step 10

Key Takeaways

O(1) Space Magic

Problems that seem to require O(n) space (storing visited nodes, counting length) can often be solved in O(1) space with fast & slow pointers.

One Loop Skeleton

All three use cases share the same while loop. Master it once: while (fast != null && fast.next != null).

Beyond Linked Lists

Any function f(x) that maps values to values can form a "virtual linked list." Happy Number and Find Duplicate both exploit this.

The Two-Phase Trick

Finding the cycle start uses two phases: (1) detect with 2x speed, (2) reset one pointer and walk both at 1x. The math guarantees they meet at the start.

The Beauty of Floyd's Algorithm

Two pointers, constant space, linear time. It turns problems that seem to need memory into problems that need only patience -- letting two runners chase each other until the structure of the problem reveals itself.