Back to all writing
DSA10 Jun 20264 min readBeginner to Intermediate

Mastering the Two Pointers Pattern

A clean decision tree for spotting two-pointer problems quickly and avoiding the most common interview slips.

arrayspointersinterviews

Two pointers is one of the first patterns that starts paying rent in interviews. The reason it matters is not that two indexes are somehow special. It matters because the pattern helps you turn a brute-force nested scan into a single directional pass.

When the pattern is a good fit

Reach for two pointers when all of the following feel true:

  • You are working on a linear structure like an array or string.
  • The answer depends on comparing elements relative to each other.
  • You can make progress by moving one boundary without losing previous work.

Common examples include:

  • Finding a pair that matches a target sum
  • Removing duplicates from a sorted array
  • Checking whether a string is a palindrome
  • Expanding or shrinking a candidate interval

Your first branch: opposite ends or same direction?

There are really two families here.

1. Opposite-end pointers

Use this when the structure is already sorted or when the order of outer characters matters.

left = 0
right = n - 1

while left < right:
  compare values
  move one or both pointers

This is the version you want for:

  • Pair sum in a sorted array
  • Container-style width decisions
  • Palindrome checks

2. Same-direction pointers

Use this when one pointer represents the next write position or the start of a cleaned-up region.

write = 0

for read in range(n):
  if should_keep(nums[read]):
    nums[write] = nums[read]
    write += 1

This is common in:

  • Remove duplicates
  • Move zeroes
  • Partitioning tasks

A fast mental checklist

Before writing code, ask:

  1. Is the input sorted, or can I sort it without breaking the problem?
  2. What exact event causes left to move?
  3. What exact event causes right to move?
  4. Am I preserving an invariant after every move?

If you cannot answer the invariant question in one sentence, pause. That is usually where bugs hide.

Invariants keep pointer problems calm. They tell you what stays true even while indices move.

A canonical example

Suppose the array is sorted and you need a pair that sums to target.

def has_pair(nums, target):
    left, right = 0, len(nums) - 1

    while left < right:
        current = nums[left] + nums[right]
        if current == target:
            return True
        if current < target:
            left += 1
        else:
            right -= 1

    return False

Why this works:

  • If the sum is too small, moving right inward would only keep the sum small or make it smaller.
  • If the sum is too large, moving left inward would only keep the sum large or make it larger.

That monotonic behavior is the reason the pattern works.

Mistakes that show up often

Moving both pointers without justification

People do this after a mismatch because it feels balanced. Usually it throws away possibilities.

Forgetting that sorting changes what you can return

If the problem asks for original indices, sorting means you now need to preserve index information.

Using the pattern where sliding window is actually the real idea

If the question is about a dynamic range with a condition on the whole interval, it may be a window problem rather than a raw pointer problem.

Practice progression

Use this order:

  1. Pair sum in sorted array
  2. Valid palindrome
  3. Remove duplicates from sorted array
  4. Squares of a sorted array
  5. Three sum after sorting

This sequence lets you feel how the invariant changes while the core intuition stays familiar.

Closing thought

Two pointers becomes reliable when you stop memorizing examples and start naming the movement rule. If you can say why each pointer moves, the implementation usually follows with much less friction.