codebrew.ai

Two Pointers Pattern: A Visual Guide to Solving Array Problems

Learn how the two pointers technique works, when to use it, and walk through classic problems like Two Sum II and Container With Most Water.

two-pointers
arrays
leetcode
patterns

Two Pointers Pattern: A Visual Guide to Solving Array Problems

The two pointers technique is one of the most versatile patterns in coding interviews. Once you see it, you'll recognise it everywhere — from simple sorted-array searches to tricky substring problems.

When to Reach for Two Pointers

Two pointers works when you can reduce a brute-force O(n²) scan to O(n) by maintaining two indices that move toward each other (or in the same direction) based on some condition.

Look for these signals:

  • The input is sorted (or can be sorted without breaking the answer).
  • You need to find a pair or subarray satisfying a constraint.
  • A brute-force nested loop compares every pair.

Classic Example: Two Sum II (Sorted Input)

Given a 1-indexed sorted array numbers and a target, find two numbers that add up to target.

python
def two_sum(numbers: list[int], target: int) -> list[int]:
    left, right = 0, len(numbers) - 1

    while left < right:
        current = numbers[left] + numbers[right]
        if current == target:
            return [left + 1, right + 1]
        elif current < target:
            left += 1
        else:
            right -= 1

    return []

Why it works: Because the array is sorted, moving left right increases the sum, and moving right left decreases it. Each step eliminates at least one candidate, giving us O(n) time.

Container With Most Water

Given heights height[0..n-1], find two lines that form a container holding the most water.

python
def max_area(height: list[int]) -> int:
    left, right = 0, len(height) - 1
    best = 0

    while left < right:
        w = right - left
        h = min(height[left], height[right])
        best = max(best, w * h)

        if height[left] < height[right]:
            left += 1
        else:
            right -= 1

    return best

The shorter line is always the bottleneck — moving it inward is the only way to possibly find a taller line, even though the width shrinks.

Same-Direction Variant: Remove Duplicates

Two pointers don't always move toward each other. In the "slow/fast" variant both move left-to-right:

python
def remove_duplicates(nums: list[int]) -> int:
    if not nums:
        return 0

    slow = 0
    for fast in range(1, len(nums)):
        if nums[fast] != nums[slow]:
            slow += 1
            nums[slow] = nums[fast]

    return slow + 1

slow marks the last unique element; fast scans ahead for the next new value.

Complexity

VariantTimeSpace
Opposite endsO(n)O(1)
Slow / fastO(n)O(1)
With sorting firstO(n log n)O(1)*

* Ignoring sort's internal space.

Practice These Next

  • 3Sum — sort + fix one element + two-pointer inner loop.
  • Trapping Rain Water — opposite-end pointers tracking max heights.
  • Linked List Cycle — slow/fast pointers (Floyd's algorithm).

Want to trace through these step-by-step with variable visualisation? Try the interactive walkthrough on Codebrew.