Fast & Slow Pointers

A pattern that moves two pointers through the same linked list at different speeds - one hop vs two - to find the middle or detect a cycle in a single O(n) pass with no extra memory.

The input is a linked list and you need to find the middle node, detect a cycle, or find where a cycle begins - without storing visited nodes. The speed difference is the entire trick.

The speed difference beats the naive set approach without extra memory

Fast and slow pointers matters because it solves linked-list problems in one pass without remembering every node you have seen. The speed gap is not just an implementation detail - it is the proof.

AspectNaive (HashSet)Fast & Slow
Cycle detectionStore every visited node in a set, check membership on each stepTwo pointers - if they ever meet, a cycle exists
TimeO(n)O(n)
SpaceO(n) - stores every nodeO(1) - just two pointers
Why it mattersWorks, but memory grows with list sizeMemory is constant regardless of list size - no set needed

If a cycle exists, the fast pointer laps the slow pointer inside the loop - they must eventually land on the same node. That is the entire proof.

See the mechanic, then the reason behind it

The card below uses the same structure as the two-pointers page: tabs, progress dots, step controls, side-by-side What / Why insight, and a fixed code panel. The linked-list motion is the only thing that changes.

O(n) timeO(1) space
List: 1 -> 2 -> 3 -> 4 -> 5 -> null
1
SLOWFAST
2
3
4
5
null
Step 1 of 4

What

Both pointers start at head (node 1).

Why

Slow will cover half the distance fast does. When fast hits the end, slow is exactly at the middle - no counting needed.

Code For This Pattern

function findMiddle(head) {
  let slow = head;
  let fast = head;

  while (fast !== null && fast.next !== null) {
    slow = slow.next;       // one hop
    fast = fast.next.next;  // two hops
  }

  return slow; // slow is at the middle
}

One speed difference solves two classic linked-list problems

The loop looks almost identical in both problems. The difference is what you are waiting for: null in one case, a meeting point in the other.

AspectFind MiddleDetect Cycle
GoalFind the midpoint without countingDetect whether next pointers loop back
Key momentWhen fast reaches nullWhen slow and fast land on the same node
Why it worksFast covers 2x the distance, so slow is halfway when fast finishesInside a cycle, fast gains 1 node per step on slow - it must catch up
Return valueslow (the middle node)true / false
ComplexityO(n) time, O(1) spaceO(n) time, O(1) space

The short version

  • The entire pattern is one insight: fast covers twice the distance of slow in the same number of steps.
  • Find Middle: when fast hits null, slow is at the exact midpoint - no length count needed.
  • Detect Cycle: inside any loop, a pointer moving 2x faster than another must eventually lap it. Meeting = cycle.
  • Both patterns use O(1) space - no array, no set, no visited map. Just two pointers.
  • If the list is null or has one node, fast hits null immediately - handle that edge case first.