As the name suggests, the two pointer technique consists of iterating an array with two indexes that move independently based on a condition.

This is useful for problems that require traversing the entire array efficiently, usually when working with pairs — e.g. comparisons, filtering, or sorting.

The implementation is very simple and straightforward:

  1. Define an index outside the main iteration loop
  2. Increment or decrement that index based on a given condition

There are three common variants, based on how the pointers move relative to each other: opposing, fast and slow, and sliding window.

TIP

Use for when iterating over a known sequence or range. Use while when the stopping condition depends on something that changes during execution.

Opposing pointers

The pointers start at opposite ends of the array and move toward each other.

For example, this is an implementation for reversing a string in-place using two pointers:

def reverse_string(s: str) -> None:
    left = 0
    right = len(s)-1
    while left < right:
        s[left], s[right] = s[right], s[left]
        left += 1
        right -= 1

NOTE

See 344. Reverse String on LeetCode.

Fast and slow pointers

Both pointers move in the same direction but at different speeds. The classic use is cycle detection on a linked list: if the fast pointer ever meets the slow one, there’s a cycle.

Sliding window

Another variation of the two pointer approach is the sliding window.

The main difference is that both indexes move in the same direction; what matters is what's between them.

It’s useful when you need to work with subarrays and track properties like length, sum, or average.

Fixed-size window

The window length stays constant. Slide it forward one step at a time, updating the aggregate by adding the new element and removing the one that fell off.

def find_max_average(nums: list[int], k: int) -> float:
    window_sum = sum(nums[:k])
    max_sum = window_sum
 
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]
        if window_sum > max_sum:
            max_sum = window_sum
 
    return max_sum / k

NOTE

TIP

What makes this technique efficient is maintaining state as the pointers move, rather than recomputing it from scratch on each step. That’s how the nested loop collapses into a single linear pass.

Variable-size window

The window grows and shrinks based on a condition: right expands it, left contracts it whenever the condition breaks. Useful for “longest/shortest subarray that satisfies X” problems.