---
title: "Fast & slow pointers"
url: https://algopath.pro/patterns/fast-slow-pointers
language: en
summary: "One pointer moves a single step at a time while the other moves two steps. The gap between them exposes cycles and midpoints."
updated: 2026-08-24
---

# Fast & slow pointers

One pointer moves a single step at a time while the other moves two steps. The gap between them exposes cycles and midpoints.

## How does Fast & slow pointers work?

Start both pointers at the head. One moves a single step per round, the other moves two.

Step them together inside one loop. Stop when the fast one runs off the end.

If the list ends, there is no cycle. A null next is the proof.

If a cycle exists, the fast pointer laps the slow one. They land on the same node.

Inside the cycle the gap shrinks by one each round. So a meeting is guaranteed.

When the fast pointer reaches the end, the slow one sits at the middle. That gives the midpoint free.

- `slow = 1, fast = 1` The list is 1 to 5. Both pointers start at the head.
- `slow = 2, fast = 3` One step against two. The gap is one node.
- `slow = 3, fast = 5` The gap is now two. The fast pointer is nearly out.
- `fast.next is null` The list ended, so there is no cycle.
- `slow = 3` The slow pointer sits on the middle node. Five nodes, middle is third.

## When should you use Fast & slow pointers?

- detect a cycle in a linked list
- find where a cycle begins
- find the middle node of a list
- determine if a list is a palindrome
- no extra memory / O(1) space, only pointers

## What is Fast & slow pointers confused with?

- **Two pointers (same direction)** - There one pointer reads and the other writes. Here both read, at different speeds.
- **Hash set / map** - A set of visited nodes also catches a cycle. It costs O(n) memory instead of O(1).
- **Linked list reversal** - Reversal rewires the links themselves. This pattern never changes a pointer in the list.
- **Graph BFS / DFS** - A traversal finds cycles in any graph, with a visited set. This works because each node has one exit.

## What is the time and space complexity of Fast & slow pointers?

n up to 1e6 gives O(n) time and O(1) space. The slow pointer never walks more than n steps.

## A worked example of Fast & slow pointers

### Where the cycle starts

A linked list may loop back into itself somewhere. Return the node where that loop begins.

If the list has no loop, return null.

First let the slow and fast pointers meet inside the loop.

Then move one pointer back to the head. Step both one at a time, and they meet at the entry.

```javascript
function detectCycle(head) {
    let slow = head;
    let fast = head;

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

        if (slow === fast) {
            // head to entry is the same distance as meeting point to entry
            let walker = head;
            while (walker !== slow) {
                walker = walker.next;
                slow = slow.next;
            }
            return walker;
        }
    }

    return null;
}
```

## Common mistakes with Fast & slow pointers

- **Checking only fast in the loop condition** Reading fast.next.next throws when fast.next is null. Test both before stepping.
- **Starting the two pointers apart** A head start changes which node they meet on. The entry proof assumes the same start.
- **Comparing values instead of nodes** Two different nodes can hold the same value. Compare the references themselves.
- **Treating the meeting point as the entry** They meet somewhere inside the loop, not at its start. A second walk finds the entry.

## Which interview problems use Fast & slow pointers?

- **Linked list cycle** The meeting itself is the whole answer.
- **Linked list cycle II** A second walk from the head finds where it enters.
- **Middle of the linked list** When fast ends, slow is standing on the middle.
- **Happy number** The digit-square step builds an invisible linked list.
- **Find the duplicate number** The array values act as next pointers.
- **Palindrome linked list** Find the middle, reverse the back half, compare.
- **Remove nth node from the end** A fixed gap instead of a doubled speed.

## JavaScript

```javascript
function hasCycle(head) {
    let slow = head;
    let fast = head;
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow === fast) return true;
    }
    return false;
}
```

## Python

```python
def has_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow is fast:
            return True
    return False
```

## PHP

```php
function hasCycle(?Node $head): bool {
    $slow = $head;
    $fast = $head;
    while ($fast !== null && $fast->next !== null) {
        $slow = $slow->next;
        $fast = $fast->next->next;
        if ($slow === $fast) return true;
    }
    return false;
}
```
