The sorted order is a free gift — use it. A left and right pointer squeeze inward from both ends; every step provably eliminates an entire candidate and converges to the answer in a single O(n) pass with O(1) extra space.
Given a sorted (non-decreasing) 1-indexed integer array numbers and an integer target, find the two numbers that add up to target and return their 1-based indices. Exactly one solution is guaranteed; you may not use the same element twice.
Example: numbers = [2, 7, 11, 15], target = 9. Numbers at indices 1 and 2 give 2 + 7 = 9, so the answer is [1, 2].
left++. If the sum is too large, the right element is useless — no left partner can bring it down. Move right--. Each step discards exactly one candidate, and the pointers meet after at most n − 1 moves.left = 0, right = n − 1 (0-indexed internally; add 1 for the answer). These are the smallest and largest candidates.sum = numbers[left] + numbers[right].sum === target, return [left + 1, right + 1].sum < target, do left++ — we need a bigger number on the left side.sum > target, do right-- — we need a smaller number on the right.[left + 1, right + 1]. Do not forget to add 1. Also do not confuse whichpointer to move: a sum that's too small needs a larger value, so advance left (not retreat right).For each numbers[i], binary-search for target − numbers[i] in the remainder. That is O(n log n) — worse than two pointers but better than brute force. Two pointers wins because the sorted invariant lets us eliminate candidates without restarting the search.
4 elements, target is 9. Place left pointer at index 1 and right pointer at index 4 (1-indexed).1function twoSum(numbers: number[], target: number): number[] {2▶ let left = 0;3▶ let right = numbers.length - 1;45 while (left < right) {6 const sum = numbers[left] + numbers[right];78 if (sum === target) {9 return [left + 1, right + 1]; // 1-indexed answer10 } else if (sum < target) {11 left++; // need a larger sum → advance left12 } else {13 right--; // need a smaller sum → retreat right14 }15 }1617 return []; // guaranteed a solution exists per constraints18}
function twoSum(numbers: number[], target: number): number[] {
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]; // 1-indexed answer
} else if (sum < target) {
left++; // need a larger sum → advance left
} else {
right--; // need a smaller sum → retreat right
}
}
return []; // guaranteed a solution exists per constraints
}left starts at 0 (the smallest element) and right at n − 1 (the largest). Together they span the entire candidate space.target?+1 converts from 0-based internal indices to the 1-based answer the problem requires.left++ replaces the smallest remaining element with the next one. Because the array is sorted, every element to the right of the new left is also larger, so the sum can only increase or stay the same — no valid pair was skipped.right-- swaps in a smaller right partner. The sort guarantee ensures nothing valid is missed on the right side either.while loop always exits via the return on line 9. The final empty array is unreachable in practice but keeps TypeScript happy.n − 1 steps total, and the pointers never reverse direction. O(1) space — only two index variables.target − x — O(n) time, O(n) space.left < right prevents that.sum === target, push the pair and advance both pointers (or handle duplicates with inner loops).numbers = [2, 7, 11, 15], target = 9." Step 1: 2 + 15 = 17 > 9 → right--. Step 2: 2 + 11 = 13 > 9 → right--. Step 3: 2 + 7 = 9 → return [1, 2].function twoSum(numbers: number[], target: number): number[] {
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]; // 1-indexed answer
} else if (sum < target) {
left++; // need a larger sum → advance left
} else {
right--; // need a smaller sum → retreat right
}
}
return []; // guaranteed a solution exists per constraints
}n − 1 steps total, and the pointers never reverse direction. O(1) space — only two index variables.Ignore the sorted order entirely: test every pair (i, j) with a double loop and return the first that sums to target — a correctness baseline before exploiting the sort.
function twoSum(numbers: number[], target: number): number[] {
const n = numbers.length;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
if (numbers[i] + numbers[j] === target) {
return [i + 1, j + 1]; // 1-indexed answer
}
}
}
return []; // guaranteed a solution exists per constraints
}i and throws away the sorted invariant. Since the array is non-decreasing, two pointers from both ends decide each element in one move, collapsing this to O(n) time and O(1) space.| sorted array + find a pair summing to X | two pointers from both ends |
| sum too small → need bigger | left++ (move toward larger values) |
| sum too large → need smaller | right-- (move toward smaller values) |
| 3Sum / k-Sum on a sorted array | fix outer elements, two-pointer inner range |
function twoSum(numbers: number[], target: number): number[] {
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];
else if (sum < target) left++;
else right--;
}
return [];
}numbers = [2, 7, 11, 15] and target = 9, trace the first step. What is the initial sum and which pointer moves?numbers = [2, 7, 11, 15], target = 9, what is the final answer after all pointer moves?