Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Fast & Slow Pointers
DSA

Fast & Slow Pointers

Learn how two pointers moving at different speeds solve cycle detection, middle-node, and related problems.

Two pointers, two speeds: slow moves 1 step, fast moves 2.

Focus on recognizing:

“Middle of list” / “cycle detection” / “no extra space allowed” → fast & slow


Pattern 1: Middle of Linked List

Two pointers, one lap speed difference — slow lands on the middle. Press to animate.

Middle of the Linked List

Return the middle node of a singly linked list using slow/fast pointers.

Run two pointers: slow advances one step, fast advances two. When fast reaches the end, slow is at the middle. For even length slow lands on the second middle.

LINKED LIST VISUALIZER
Steps
12345
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        slow = fast = head
                      
                        2
                        while fast and fast.next:
                      
                        3
                          slow = slow.next
                      
                        4
                          fast = fast.next.next
                      
                        5
                        return slow
                      

When fast hits the end, slow is at the 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;
}
def middle_node(head):
    slow = fast = head

    while fast and fast.next:
        slow = slow.next       # 1 step
        fast = fast.next.next  # 2 steps

    return slow
ListNode* middleNode(ListNode* head) {
    ListNode *slow = head, *fast = head;

    while (fast && fast->next) {
        slow = slow->next;     // 1 step
        fast = fast->next->next; // 2 steps
    }

    return slow;
}
function middleNode(head) {
  let slow = head,
    fast = head;

  while (fast && fast.next) {
    slow = slow.next; // 1 step
    fast = fast.next.next; // 2 steps
  }

  return slow;
}

Even length → returns the second middle. Use fast.next.next start conditions to pick the first.


Pattern 2: Cycle Detection + Cycle Start

Floyd’s detectors chasing each other through a loop — the gap closes by one each round until they land on the same node. Press to animate.

Fast & Slow Pointers

Use two pointers moving at different speeds to locate the middle of a list and to detect cycles.

slow advances one step while fast advances two; when fast reaches the end, slow is exactly at the middle.

LINKED LIST VISUALIZER
Steps
12345
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        slow = fast = head
                      
                        2
                        while fast && fast.next:
                      
                        3
                          slow = slow.next      // 1 step
                      
                        4
                          fast = fast.next.next // 2 steps
                      
                        5
                        return slow              // middle
                      

Floyd’s algorithm — if they meet, there’s a cycle:

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

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

        if (slow == fast) return true;
    }

    return false;
}
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
bool hasCycle(ListNode* head) {
    ListNode *slow = head, *fast = head;

    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;

        if (slow == fast) return true;
    }

    return false;
}
function hasCycle(head) {
  let slow = head,
    fast = head;

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

    if (slow === fast) return true;
  }

  return false;
}

To find where the cycle starts: after they meet, reset one pointer to head and walk both 1 step — they meet again at the entry node.


Relative speed 1 guarantees a meeting inside any cycle — that’s why it terminates.


Pattern 3: Palindrome Linked List

Find mid, reverse the tail, compare halves — O(1) space. Press to animate.

Palindrome Linked List

Check whether a singly linked list reads the same forwards and backwards.

Use slow/fast to find the middle, reverse the second half, then compare node-by-node with the first half. This keeps O(1) extra space versus a stack or HashSet.

LINKED LIST VISUALIZER
Steps
1221
Press ▶ to animate, or step through manually.
Variables
keys: ← → space F
Pseudocode

                        1
                        slow/fast run → slow lands at mid
                      
                        2
                        reverse second half
                      
                        3
                        compare head vs mid2 stepwise
                      
                        4
                        match all → palindrome
                      

Find middle → reverse second half → compare halves:

public boolean isPalindrome(ListNode head) {
    // 1. find middle
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }

    // 2. reverse second half
    ListNode prev = null;
    while (slow != null) {
        ListNode next = slow.next;
        slow.next = prev;
        prev = slow;
        slow = next;
    }

    // 3. compare halves
    while (prev != null) {
        if (head.val != prev.val) return false;
        head = head.next;
        prev = prev.next;
    }

    return true;
}
def is_palindrome(head):
    # 1. find middle
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

    # 2. reverse second half
    prev = None
    while slow:
        slow.next, prev, slow = prev, slow, slow.next

    # 3. compare halves
    while prev:
        if head.val != prev.val:
            return False
        head, prev = head.next, prev.next

    return True
bool isPalindrome(ListNode* head) {
    // 1. find middle
    ListNode *slow = head, *fast = head;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
    }

    // 2. reverse second half
    ListNode* prev = nullptr;
    while (slow) {
        ListNode* next = slow->next;
        slow->next = prev;
        prev = slow;
        slow = next;
    }

    // 3. compare halves
    while (prev) {
        if (head->val != prev->val) return false;
        head = head->next;
        prev = prev->next;
    }

    return true;
}
function isPalindrome(head) {
  // 1. find middle
  let slow = head,
    fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }

  // 2. reverse second half
  let prev = null;
  while (slow) {
    const next = slow.next;
    slow.next = prev;
    prev = slow;
    slow = next;
  }

  // 3. compare halves
  while (prev) {
    if (head.val !== prev.val) return false;
    head = head.next;
    prev = prev.next;
  }

  return true;
}

O(1) space — the list ends up half-reversed, which most interviewers accept (restore it if asked).


Common Mistakes

while (fast.next != null) without checking fast.

On an even-length list fast becomes null first → NullPointerException.


Comparing values to detect cycles.

Nodes can repeat values — compare references (==), never .val.


Forgetting the meeting-point math for cycle start.

Reset ONE pointer to head, move both 1 step — don’t restart fast at 2× speed.


Complexity

OperationTimeSpace
MiddleO(n)O(1)
Cycle detectO(n)O(1)
PalindromeO(n)O(1)

My Private Notes

Notes are auto-saved locally to this device.