Two Pointers

A technique that places two markers on the same array and moves them according to a simple rule - often turning an O(n^2) nested loop into a single O(n) pass.

The input is a sorted array or string, or the problem asks you to find a pair or subarray satisfying a condition. If you catch yourself writing a nested loop to compare every pair, stop. Two pointers likely cuts it to one pass.

The motivation should be clear before the demo starts

Two pointers is worth learning because it replaces pair-by-pair brute force with a controlled one-pass rule. You are not just moving pointers around. You are using structure in the input to throw away work.

Brute force: O(n^2)
Nested loop. Check every pair. About 500K comparisons on n = 1,000.

You compare one element against every other candidate.

The work grows quadratically because the search space is never discarded.

Two pointers: O(n)
One pass. Each pointer moves at most n times. About 1K comparisons on n = 1,000.

Every comparison gives you a rule for what can be safely ignored next.

The total movement is linear because the pointers never need to backtrack.

See the move, then see the reason behind it

The demo is split into the two core variants of the pattern. Every step explains both what the algorithm just did and why that move was logically correct.

O(n) timeO(1) space
Array: [1, 2, 4, 6, 8, 10]Target = 9
01
Left
12
24
36
48
510
Right
Step 1 of 4

What

Pointers placed at both ends.

Why

The array is sorted, so moving left grows the sum and moving right shrinks it. That gives us a decision rule for every step.

Code For This Pattern

let left = 0;
let right = nums.length - 1;

while (left < right) {
  const sum = nums[left] + nums[right];

  if (sum === target) {
    return [left + 1, right + 1]; // LeetCode #167 is 1-indexed
  }

  if (sum < target) {
    left += 1; // Need a larger sum
  } else {
    right -= 1; // Need a smaller sum
  }
}

Opposite direction and same direction solve different jobs

Both versions use two markers on the same array, but the movement rule is different. The best clue is the type of question the problem is asking.

AspectOpposite DirectionSame Direction
Starting layoutOne at each endBoth start left
Decision ruleMove the pointer whose side can be eliminatedMove fast always; slow only on a new unique value
Best forPair sums, palindromes, container problemsDeduplication, partitioning, in-place compaction
Classic problemsTwo Sum II, Valid Palindrome, 3SumRemove Duplicates, Move Zeroes, Merge Sorted Array
ComplexityO(n) time, O(1) spaceO(n) time, O(1) space

The short version

  • Reach for two pointers when the input is sorted and you need a pair or to compact an array.
  • Opposite direction: each comparison tells you which side to discard. Search space provably shrinks every step.
  • Same direction: fast reads every element; slow only advances on a new unique value. No backtracking.
  • Both patterns: O(n) time, O(1) space. No extra array, no nested loop.
  • If the array is unsorted, sort it first. O(n log n) sort is still far cheaper than O(n^2) brute force.