Arrays · Core Array Techniques

Two Pointers

Using two indices that move toward or away from each other to avoid an inner loop, typically on sorted data.

  • 5 min read
  • 8 practice questions
  • 5 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: running maximums
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Two pointers walks two indexes through an array at once, usually from opposite ends toward each other. At each step, something the input guarantees, most often that it's sorted, tells you which index to move. Each step rules out a whole group of candidate pairs, so a search that looks like O(n^2) becomes one O(n) pass. It's the idea behind Two Sum on a sorted array, 3Sum and 4Sum, merging sorted arrays, and Trapping Rain Water.

We'll go from simple to more technical:

  1. The pattern: two indexes closing in on a target sum.
  2. A second flavor: comparing two running maximums (Trapping Rain Water).
  3. Where the same walk shows up in production code.
  4. When it applies, and the mistakes that make it silently wrong.

The approach

Checking every pair finds a pair with a given sum, but it takes O(n^2) time and ignores the fact that the array is sorted. Start instead with left at the smallest value and right at the largest. If their sum is too small, move left up to get a bigger sum. If it's too big, move right down. Stop when they meet.

Find two values that add up to 10 in [1, 3, 4, 6, 8, 11]:

leftrightSumMove
11112too big: right down
189too small: left up
3811too big: right down
369too small: left up
4610found

Java

int left = 0, right = nums.length - 1;
while (left < right) {
    int sum = nums[left] + nums[right];
    if (sum == target) { /* found it */ break; }
    else if (sum < target) left++;   // need a bigger sum
    else right--;                    // need a smaller sum
}

Python

left, right = 0, len(nums) - 1
while left < right:
    total = nums[left] + nums[right]
    if total == target:
        break           # found it
    elif total < target:
        left += 1       # need a bigger sum
    else:
        right -= 1      # need a smaller sum

Why is it safe to throw a value away? Say 1 + 8 is too small. Then 1 can't be part of the answer: its biggest remaining partner, 8, already wasn't enough. So left moves past it. Each step drops one value for good, which is why the walk takes at most n - 1 steps.

A second flavor: running maximums

Not every two-pointer problem has a target. Trapping Rain Water asks how much water collects between bars of different heights. It also moves two pointers inward, but each step compares two running maximums: the tallest bar seen so far from the left and from the right.

Java

int left = 0, right = height.length - 1;
int leftMax = 0, rightMax = 0, water = 0;
while (left < right) {
    leftMax = Math.max(leftMax, height[left]);
    rightMax = Math.max(rightMax, height[right]);
    if (leftMax < rightMax) {
        water += leftMax - height[left];   // bounded by the SMALLER known max
        left++;
    } else {
        water += rightMax - height[right];
        right--;
    }
}

Python

left, right = 0, len(height) - 1
left_max = right_max = water = 0
while left < right:
    left_max = max(left_max, height[left])
    right_max = max(right_max, height[right])
    if left_max < right_max:
        water += left_max - height[left]    # bounded by the SMALLER known max
        left += 1
    else:
        water += right_max - height[right]
        right -= 1

The water above a bar is limited by the shorter of the tallest bar to its left and the tallest bar to its right. Suppose leftMax is smaller. The right side already has a wall at least that tall, and more bars can only make it taller. So the water at left is settled, and that pointer can move. For heights [2, 0, 3, 1, 0, 4] the walk collects 7 units.

You'll also see a version that compares the current bars, height[left] < height[right]. It's correct too, but comparing the running maximums states the reason directly.

Where you'll see it

Merging two sorted result sets is a two-pointer walk: two pages of database results, or two sorted log streams in a reconciliation job. So is finding overlapping time ranges once both lists are sorted by start time.

Which tool for which job?

You needUse
A pair with a given sum in a sorted arraytwo pointers from both ends
A pair with a given sum in an unsorted array, with original indicesa hash map in one pass
All triplets or quadruplets with a sumsort, fix the outer indices, two pointers inside
Merging two sorted arrays or listsone pointer per input, take the smaller
Water trapped between barstwo pointers comparing running maximums
A contiguous range with some propertya sliding window (the next skill)

Common mistakes

MistakeWhat happensDo this instead
Running it on unsorted inputa wrong answer, no errorsort first, or use a hash map
No duplicate skipping in 3Sum/4Sumthe same triplet is reported twiceafter a match, skip equal values on both sides
Sorting when the answer needs original indicesthe indices point into the sorted copysort (value, index) pairs, or use a hash map
Summing four large ints in Javathe sum overflows and compares wronglyadd in a long
left <= right in a pair searchan element is paired with itselfloop while left < right

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. You run the pair search on an array that's sorted except for one pair of neighbors. What happens?

Show answer

Nothing crashes. The code still returns an answer, but the rule for which pointer to move assumes sorted order. Near the out-of-order pair that's no longer true, so the answer can be silently wrong. No error and no obviously bad output make it the most dangerous kind of bug.

2. Why does 3Sum need to skip duplicates when the plain pair search doesn't?

Show answer

The pair search returns one pair and stops. 3Sum collects every triplet, and a sorted array can hold the same value at several indexes. Without skipping equal values after a match, the same triplet of values is reported again from different indexes.

3. Trapping Rain Water has no target. What decides which pointer moves?

Show answer

The two running maximums. The side with the smaller one moves, because the water at its pointer is already settled. Nothing still unseen on the other side can lower that limit.

Key takeaways

  • Two pointers turns an O(n^2) pair search into one O(n) pass by using sorted order (or a running maximum) to drop a value at every step.
  • On unsorted input it returns wrong answers without crashing.
  • 3Sum and 4Sum must skip duplicates after each match.
  • Trapping Rain Water moves the side whose running maximum is smaller.
  • Without some order to rely on, there's no safe rule for which pointer to move.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
A pair sum in a sorted arraytwo pointers from both ends
A pair sum in an unsorted array, with indicesa hash map
3Sum / 4Sumsort, fix outer indices, two pointers inside
Merge two sorted inputsone pointer each, take the smaller
Trapped watercompare the running maximums
Most water between two barsmove the shorter bar

Snippets worth knowing by heart

Java

int left = 0, right = nums.length - 1;
while (left < right) {
    long sum = (long) nums[left] + nums[right];   // long: no overflow
    if (sum == target) return new int[] {left, right};
    if (sum < target) left++;                     // need a bigger sum
    else right--;                                 // need a smaller sum
}

Python

left, right = 0, len(nums) - 1
while left < right:
    total = nums[left] + nums[right]
    if total == target:
        return [left, right]
    if total < target:
        left += 1        # need a bigger sum
    else:
        right -= 1       # need a smaller sum

The traps

  • Unsorted input: the pointer moves lose their meaning, so answers are wrong with no error. Sort first, or use a hash map.
  • No duplicate skipping in 3Sum/4Sum: the same triplet is reported twice. After a match, skip equal values on both sides.
  • Sorting away the original indices: indices point into the sorted copy. Sort (value, index) pairs.
  • int overflow in Java sums: four large values wrap and compare wrongly. Add in a long.
  • left <= right: an element pairs with itself. Loop while left < right.

Staff-level points, one line each

  • Each move rules out a whole row or column of pairs: at most n - 1 steps.
  • Counting pairs below a target: add right - left; 1,065,266 pairs counted in 1,999 steps.
  • Container With Most Water: move the shorter bar; matched the brute force on 400 heights.
  • k-Sum is O(n^(k-1)); skip duplicates at every level.
  • 2,000,000,000 + 2,100,000,000 as Java ints was -194967296 - add in a long.
  • Sorting first costs O(n log n) and the original indices.

Say it in an interview

  • "The array is sorted, so if the sum is too small, nothing paired with left can work - I move left."
  • "Each step discards a whole row of pairs, so it's O(n) with O(1) extra space."
  • "For 3Sum I sort, fix one index, and skip duplicates on every level."
  • "If I need original indices from unsorted input, I'd use a hash map instead."

Practice

This skill comes with 8 multiple-choice questions that tell you which misconception a wrong answer reveals and 5 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Two Pointers free

Merge Sorted Array

EasyFreeCoding problemJava · Python

You are given two sorted integer arrays. The first, conceptually of length m + n, has its first m elements set and its last n elements available as placeholder space; the second has n elements.

Two Sum — Sorted Array

MediumProCoding problemJava · Python

You get a list of integers nums in non-decreasing order and a number target. Exactly one pair of different positions holds two values that add up to target. Report those two positions, counting from 1, the smaller position first.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

4Sum

MediumProCoding problemJava · Python

Given an array nums and an integer target, return every unique quadruplet [a, b, c, d] (using four distinct indices) such that a + b + c + d == target.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

3Sum

MediumProCoding problemJava · Python

Given an array nums, return every unique triplet [a, b, c] (using three distinct indices) such that a + b + c == 0. No two triplets in the output may be the same set of values; each triplet's values must be sorted ascending, and the overall list also sorted ascending.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Trapping Rain Water

HardProCoding problemJava · Python

Picture a row of walls of different heights, each one unit wide, standing side by side. After a heavy rain, water collects in every dip between taller walls. Given the wall heights from left to right, work out how many units of water stay trapped.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Two Pointers free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime