Skip to content

#167MediumTwo pointers

Two Sum II - Input Array Is Sorted

View on LeetCode ↗

Start dumb: try every pair

Two positions, one target sum — the honest first idea is the double loop: for every i, try every j > i and test numbers[i] + numbers[j] == target. That’s O(n²) comparisons, and it treats the input as an arbitrary bag of numbers.

Find the bottleneck

The brute force ignores the one gift this problem hands you: the array is sorted. Sortedness makes the pair sum predictable — you always know which direction a pointer move pushes it. Testing pairs in arbitrary order throws that signal away and re-learns nothing from each failed comparison.

The optimal shape

Two pointers converge from the ends of the array:

  1. Compute the sum of the two pointed-at values.
  2. Exact hit → done (report 1-based positions).
  3. Too small → only moving left rightward can raise the sum.
  4. Too big → only moving right leftward can lower it.

Each step retires one value, so the pointers cross after at most n − 1 moves — O(n) time and, unlike the hash-map Two Sum, O(1) space: sortedness replaces the lookup table. Watch the window between the pointers in the player below — it only ever shrinks, never re-expands. That one-way collapse is the proof.

Watch it think

Step through the default input, then probe the edges: duplicates (3,3 | 6), negatives (-3,3,4 | 0), an impossible target (1,2,3 | 100), or an unsorted list — the player will tell you why sortedness is non-negotiable.

Re-traces as you type — comma-separated non-decreasing integers (2–14), a pipe, then the target — e.g. "2,7,11,15 | 9". Capped at 32 characters so the tiles stay readable.

Step 1 of 7: The two ends form the widest pair — every other pair sits strictly inside it, so nothing has been ruled out yet. Variables: left = 0, right = 3, sum = —, target = 9.

Data

Code

1fun twoSum(numbers: IntArray, target: Int): IntArray {
2 var left = 0
3 var right = numbers.lastIndex
4 while (left < right) {
5 val sum = numbers[left] + numbers[right]
6 when {
7 sum == target -> return intArrayOf(left + 1, right + 1)
8 sum < target -> left++
9 else -> right--
10 }
11 }
12 return intArrayOf(-1, -1)
13}

State

left
0
right
3
sum
target
9

Why this step

The two ends form the widest pair — every other pair sits strictly inside it, so nothing has been ruled out yet.

1 / 7

Recognize the window, and these fall to the same skeleton.

  • Two Sum (LC 1) ↗

    The "what if it weren't sorted?" pivot — without sorted order you fall back to the O(n) hash map and pay O(n) space for the lookup table.

  • 3Sum (LC 15) ↗

    Fix one element, then run this exact converging-pointer sweep on the remainder — the natural escalation to a harder variant.

  • 3Sum Closest (LC 16) ↗

    Same sweep, but instead of stopping on an exact hit you track the nearest sum seen so far.

  • 4Sum (LC 18) ↗

    Fix two elements with nested loops and the innermost layer is still this two-pointer skeleton.