Two Sum II

Naseebullah Ahmadi  Senior Software Engineer, London

A sorted array, two pointers closing in from both ends, and a proof that whichever side is off-target can be ruled out entirely rather than retried against a smaller search space.

8 min read
#algorithms
In one line

Walk in from both ends of a sorted array: the sum tells you exactly which side is hopeless, and only one direction can ever help.

time O(n)space O(1)

Given a sorted array and a target, find the pair of values that adds up to it, and return their positions. A brute-force scan checks every pair: that's O(n2)O(n^2), and it never uses the fact that the array is sorted.

Two pointers gets it down to a single pass. It starts at the two ends and proves, at every step, that one of them can be discarded for good.

Why the sum tells you which pointer to move

Discard the extreme pointer

  • If the sum is too big, the right value is too big to pair with left. And since left is already the smallest value left in play, that value is too big for every remaining candidate.
  • If the sum is too small, the same argument runs in reverse: the left value is too small to pair with anything left of right.
  • Each comparison rules out an entire diagonal of pairs, not just the one just tested.

What it does not prove

  • It doesn't say the pointer's next position is the answer, only that keeping the old one is hopeless.
  • It needs a single, fixed target and a total order (>/<) to compare against. It doesn't extend to "closest sum" without tracking a running best instead of stopping early.
Signals in the problem statement
  • "sorted array" or "input array is sorted"
  • a single target sum, with exactly one valid pair guaranteed
  • asked to return positions/indices, not just whether a pair exists
  • "constant extra space" ruling out a hash map

The pattern

  1. 1Place pointers at index 0 and n - 1.
  2. 2Compare the sum at the current pair against the target.
  3. 3

    Sum too big → move right left. Sum too small → move left right.

  4. 4Stop when the pointers meet, or the sum matches.
@itsnas two-sum.ts
codetwo-sum.ts
// Returns 1-indexed positions, per the sorted Two Sum convention.
function twoSum(
  numbers: number[],
  target: number,
): [number, number] | null {
  let left = 0
  let right = numbers.length - 1
 
  while (left < right) {
    const sum = numbers[left] + numbers[right]
    if (sum === target) return [left + 1, right + 1]
    if (sum < target) left++ // left is too small for anything remaining
    else right-- // right is too big for anything remaining
  }
 
  return null
}
main
Nas (@itsnas)

Complexity

Time

Each element is visited at most once as the pointers close in.

Space

Just the two indices, no hash map, no auxiliary array.

The unsorted version of this problem needs a hash map: O(n)O(n) time but also O(n)O(n) space. Sorting first (if it isn't already) trades that space back for O(nlogn)O(n \log n) up front.

Common pitfalls

  1. 1

    Off-by-one on the return format

    The classic sorted Two Sum asks for 1-indexed positions, not array indices: a correct pointer walk with the wrong offset still fails every test.

  2. 2

    Moving the wrong pointer

    Moving left when the sum is too big (or right when it's too small) inverts the invariant and can walk straight past the answer without ever detecting it.

  3. 3

    Using `left <= right` as the loop guard

    A pair needs two distinct indices: letting the pointers land on the same slot means checking a value against itself.

  4. 4

    Assuming order that isn't there

    If the input isn't actually sorted by value (or is sorted by something else, like original index), the pointers silently give the wrong answer instead of an error.

Variants worth knowing

  1. 1

    Unsorted Two Sum: no order to exploit, so trade the O(1)O(1) space for a hash map instead.

  2. 2

    3Sum: fix one value, then run this exact pattern on the rest with a moving target.

  3. 3

    Closest to target: track the best difference seen so far instead of stopping at an exact match.

Practice, easiest first


End of entry · Keep exploring

What's next in the notebook?

Keep reading — more from where that came from.

Featured next
8 min read
0%

Valid Triangle Number

Sort the side lengths, fix the largest one at a time, and let the gap between two pointers count every valid pair against it in one step instead of testing them one by one.

12 min read
#algorithms

3Sum

Sort the array, fix one value as a moving target, and reuse the exact two-pointer proof from Two Sum II to sweep the rest, with a couple of extra duplicate-skipping rules layered on top.

0%
7 min read
#algorithms

Container With Most Water

A row of walls, two pointers starting at the widest container, and a proof that moving the taller wall can never beat what you already have, so only the shorter side is ever worth moving.

0%
7 min read
#algorithms

Two Pointers

Two indices walking through one ordered structure, discarding the side that cannot improve the answer at every step and replacing a nested loop with a single pass.

0%