Skip to main content

Two Pointers: Eliminate Candidates Safely

Two pointers are roles, not an algorithm by themselves. They may bound a pair, partition processed output from unread input, or move at different speeds through a linked structure. A useful solution explains why a pointer can advance without discarding the answer; two indices alone do not establish linear time or correctness.

FrontendInterviews.dev Updated

Recognize the Pattern

  • Sorted order lets a comparison rule eliminate an entire family of pairs.
  • In-place stable compaction separates a read position from the next write position.
  • A boundary's limiting value or relative pointer speed provides a proof that does not require sorted input.

Core Invariant

After measuring a container, retaining its shorter side while moving the other endpoint inward cannot improve that pair's area.

Important Boundary

Pointer roles need different proofs. Do not sort container heights, or apply sorted-pair movement to unsorted values.

Heights 1,8,6,2,5,4,8,3,7 with indices 1 and 8 bounding width 7 and height 7.
Indices 1 and 8 enclose area 7 x 7 = 49. These are container sides, not a histogram rectangle over adjacent bars.

Choose roles before movement

Sliding windows are a related same-direction technique for contiguous ranges, covered separately. Container heights do not need to be sorted: their elimination proof comes from the shorter side. Sorting them would destroy the original widths.

RolesExampleReason to move
Opposite endsSorted pair sumToo-small sum eliminates the current left value with all remaining right values.
Read and writeMove ZeroesThe written prefix already contains every kept value in original order.
Slow and fastLinked List CycleWithin a cycle, the relative offset changes by one per step.
Two limiting sidesContainer With Most WaterKeeping the shorter side and narrowing cannot improve this pair's area.

Move the side that cannot improve

Suppose the left height is no greater than the right height. Any container retaining that left side and moving the right endpoint inward has a smaller width and height at most the old left height. Its area cannot beat the pair just measured, so discard the left side. When heights tie, either side is safe to discard.

Template Assumptions

  • Nonnegative numeric heights at original unit-spaced positions; fewer than two heights returns zero.
  • Finds maximum area only, without changing the input or returning endpoint indices.
JavaScript Template
function maxArea(heights) {
  let left = 0, right = heights.length - 1, best = 0;
  while (left < right) {
    const height = Math.min(heights[left], heights[right]);
    best = Math.max(best, height * (right - left));
    if (heights[left] <= heights[right]) left++;
    else right--;
  }
  return best;
}

Follow the shorter side, not the taller one

Left, rightLimiting heightAreaMove
0,818left to 1
1,8749right to 7
1,7318right to 6
1,6840left to 2 (tie)
2,6624left to 3
3,626left to 4
4,6510left to 5
5,644left to 6; stop

Step-by-Step: Container area: measure, then move the shorter side

Step 1 / 9
10L8162235445863778R
Left, right
0,8
Width and limiting height
8, 1
Current area
8
Best area
8

Measure sides 0 and 8

Area = 1 x 8 = 8. Best is 8. Move the shorter left side. Retaining that side while narrowing the width cannot beat the pair just measured.

Preserve identity and duplicate policy

  • For sorted pair sum, keep left < right so an item cannot pair with itself. Sorting original values loses original indices unless you retain index records.
  • For Three Sum, sort, fix one value, then search pairs. Skip repeated anchors and repeated pair values only after accounting for a result. Its scan is O(N squared), not O(N).
  • For Move Zeroes, advance write only when keeping a value; fill the remaining suffix afterward. This preserves nonzero order.
  • Floyd's cycle detection needs null checks before advancing fast.next.next. It answers a linked-structure question, not a window question.

Separate preprocessing from scanning

  • The container scan is O(N) time and O(1) auxiliary space, with no sorting or mutation.
  • A sorted pair scan is O(N), but comparison sorting first conventionally costs O(N log N). Copies and index records require O(N) storage.
  • Stable compaction and Floyd's cycle test are linear with constant auxiliary state; enumerate the extra output storage separately.

Mistakes and Counterexamples

Move the taller container side first.

Counterexample: For [1,2,4,3], discarding the right side at pair (0,3) skips the best pair (1,3), with area 4.

Correction: Eliminate the shorter side, whose fixed height cannot compensate for reduced width.

Apply sorted pair movement to unsorted data.

Counterexample: For [3,2,4] and target 6, an opposite-end scan can discard 4 before finding the valid pair 2 + 4.

Correction: Establish the ordering condition, or use a hash map when original order and indices must remain intact.

Last-Minute Recap

  • Give each pointer a role.
  • Prove the eliminated candidates cannot improve the answer.
  • Sorted-pair, compaction, cycle, and container proofs are different.
  • Include sorting, repeated scans, and output costs.

Explain It in an Interview

  1. Which family of candidates does your pointer move eliminate?
  2. Why is either move safe when container heights tie?
  3. How does a read/write invariant differ from opposite-end pair search?

Ready to Apply This Pattern?

Before coding, explain why this pattern fits and what must stay true at each step. Start with an easier problem, then test that reasoning on a harder variation.

Ordered from Easy to Hard. Premium access requirements still apply.

References