AlgoInsight

Free lesson · DSA Mastery - Interview Prep, End to End

Introduction to Two Pointers

Medium6 min readdsatwo-pointers

Introduction to Two Pointers

Two pointers is one of the most elegant techniques in the interview toolkit. The idea is deceptively simple: instead of one index walking through an array, you use two indices moving in a coordinated way. That small change turns many O(n²) brute-force solutions into O(n) ones, often while dropping the space cost to O(1).

This chapter gives you the mental model. The two flavors, when each applies, and the patterns that show up over and over. Most two-pointer problems are variations on a handful of templates; once you've internalized them, recognizing the technique becomes automatic.

Why Two Pointers Matters

There are three reasons interviewers love two-pointer problems:

  1. They reward insight over brute force. The brute-force solution is usually obvious (nested loops). The two-pointer solution requires you to notice some structure - sortedness, symmetry, monotonicity - that lets you avoid redundant work. Spotting that structure is the test.

  2. They optimize both time and space. Many two-pointer solutions are O(n) time and O(1) space - strictly better than hash-based alternatives that cost O(n) space. When an interviewer asks "can you do it without extra space?", two pointers is often the answer.

  3. They generalize. The same skeleton solves Two Sum (sorted), 3Sum, 4Sum, Container With Most Water, Trapping Rain Water, and dozens more. Learning the template once pays off across a huge range of problems.

For interviews, two-pointer problems are roughly 10-15% of array and string questions. The technique is also a building block for sliding window (Section 12), which is essentially "two pointers moving in the same direction with a maintained invariant."

The Two Flavors

Interactive animation: The two flavors moving: toward each other from the ends, or a fast reader ahead of a slow writer.

Almost every two-pointer problem falls into one of two categories.

Flavor 1: Opposite Direction (Converging Pointers)

Two pointers start at opposite ends of the array and move toward each other. They meet (or cross) in the middle.

left →                    ← right
[ a, b, c, d, e, f, g, h, i, j ]

When to use it:

Canonical examples: Two Sum II (sorted), Container With Most Water, Valid Palindrome, 3Sum, Trapping Rain Water.

The key decision in opposite-direction problems is: which pointer do I move, and why? The answer almost always comes from a comparison that tells you one side can't possibly improve the answer, so you move past it.

Interactive animation: Every pair on one grid: each comparison rules out a whole row or column, so the pair is never skipped.

Flavor 2: Same Direction (Fast and Slow)

Both pointers start at (or near) the same end and move in the same direction, but at different speeds or under different conditions. One pointer (often called "slow" or "write") trails the other (often "fast" or "read").

slow →
fast →
[ a, b, c, d, e, f, g, h, i, j ]

When to use it:

Canonical examples: Remove Duplicates from Sorted Array, Move Zeroes, Merge Sorted Array, Backspace String Compare, String Compression.

The key insight in same-direction problems is that the slow pointer maintains a partition invariant: everything before slow is "finalized" (already processed/written), and the fast pointer explores what comes next.

The Pattern Catalog

Interactive animation: The five templates, each with its own live motion.

Five concrete patterns cover most two-pointer problems.

Pattern 1: Converge to Find a Pair

Sorted array, looking for two elements satisfying a condition.

int left = 0, right = n - 1;
while (left < right) {
    int sum = arr[left] + arr[right];
    if (sum == target) return new int[]{left, right};
    else if (sum < target) left++;   // need a bigger value
    else right--;                     // need a smaller value
}

The comparison decides which pointer moves. If the sum is too small, the only way to increase it is to move left rightward (toward larger values). If too big, move right leftward.

Pattern 2: In-Place Filter (Slow/Fast)

Keep elements matching a condition, compacting them to the front.

int slow = 0;
for (int fast = 0; fast < n; fast++) {
    if (keep(arr[fast])) {
        arr[slow] = arr[fast];
        slow++;
    }
}
// arr[0..slow-1] holds the kept elements

The slow pointer is the write position; fast reads through everything. This is O(n) time, O(1) space.

Pattern 3: Merge Two Sequences

Walk two sorted arrays with one pointer each, picking the smaller element.

int i = 0, j = 0;
while (i < a.length && j < b.length) {
    if (a[i] <= b[j]) result.add(a[i++]);
    else result.add(b[j++]);
}
// append remaining elements from whichever array isn't exhausted

Pattern 4: Expand From Center

For palindrome problems, place two pointers at a center and expand outward while characters match.

int left = center, right = center;
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
    left--;
    right++;
}
// palindrome spans (left+1, right-1)

Pattern 5: Fixed One, Scan With Two (Nested Two Pointers)

For 3Sum and 4Sum, fix one (or two) elements with an outer loop, then use opposite-direction two pointers for the rest.

for (int i = 0; i < n - 2; i++) {
    int left = i + 1, right = n - 1;
    while (left < right) {
        // two-pointer logic for the remaining target
    }
}

This reduces a problem that looks O(n³) to O(n²).

When to Reach for Two Pointers

The most reliable signal: the array is sorted, and you're looking for a pair or a structure based on values. Sorting lets you reason about direction - if the current candidate is too small, you know which way to move.

Other signals:

Counter-signals where two pointers usually doesn't fit:

Interactive animation: Read the signal in the question, then pick the flavor or the tool.

Two Pointers vs. Hashing vs. Sliding Window

A quick comparison of the three most common linear-scan techniques:

Property Two Pointers Hashing Sliding Window
Typical time O(n) or O(n²) O(n) O(n)
Typical space O(1) O(n) O(1) or O(k)
Needs sorted input? Often yes No No
Preserves original indices? Sometimes Yes Yes
Best for Pairs in sorted data, in-place ops Lookups, counting Contiguous subarrays

The decision:

These techniques also combine. 3Sum uses sorting + two pointers. Some problems use a hash set inside a two-pointer scan. Don't think of them as mutually exclusive.

Interactive animation: The comparison table as a matrix: time, space, sorted input, original indexes.

Common Pitfalls With Two Pointers

Interactive animation: The worst pitfall: when the sum is too small, only left can raise it.

A few things that trip up candidates:

Moving the wrong pointer. In opposite-direction problems, the comparison dictates which pointer moves. Move the wrong one and you'll skip valid answers. Always reason: "if I move this pointer, does my objective move in the right direction?"

Infinite loops. If neither pointer advances in some branch, the loop never terminates. Make sure every iteration moves at least one pointer.

Off-by-one in the loop condition. left < right vs left <= right matters. Use < when the two pointers shouldn't point to the same element (e.g., pair-finding); use <= when a single middle element is valid (rare).

Forgetting to skip duplicates. In 3Sum and 4Sum, failing to skip duplicate values produces duplicate result tuples. The skip logic is fiddly but essential.

Assuming sorted when it isn't. Two-pointer convergence relies on sortedness. If the input isn't sorted, either sort it first (and accept the O(n log n) cost and index loss) or use a different technique.

What This Section Covers

The 16 problem topics in Module 10 are organized by flavor:

By the end of Module 10, you'll be able to recognize when two pointers applies, decide which flavor to use, and implement the standard templates cleanly. The technique recurs throughout the rest of the course - in linked lists (Section 15), sliding window (Section 12), binary search (Section 21), and many others.

Let's start with a gentle warm-up: Squares of a Sorted Array, where opposite-direction pointers handle the negative-number twist elegantly.

Back to DSA Mastery - Interview Prep, End to End