Two Sum II - Input Array Is Sorted

Problem

Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Return the indices of the two numbers as an integer array [index1, index2] of length 2, where 1 <= index1 < index2 <= numbers.length. You may assume that each input would have exactly one solution and you may not use the same element twice.

  • 2 ≤ numbers.length ≤ 3 * 10⁴
  • −1000 ≤ numbers[i] ≤ 1000
  • numbers is sorted in non-decreasing order
  • −1000 ≤ target ≤ 1000
  • Exactly one valid answer exists

Example

Input: numbers = [2,7,11,15], target = 9
Output: [1, 2]

Starting with pointers at the beginning (index 0) and end (index 3) of the array, the algorithm calculates the sum: 2 + 15 = 17, which is greater than the target 9. Since the array is sorted, decreasing the right pointer moves to a smaller number. Moving right pointer from index 3 to 2, sum becomes 2 + 11 = 13, still greater than 9. Move right pointer again to index 1, sum is 2 + 7 = 9, which matches the target. The algorithm returns [1, 2] (1-indexed). The critical insight is that the sorted property allows discarding one pointer at each step, avoiding a quadratic search.

Approach

Straightforward Solution

A brute-force approach checks all pairs with nested loops, resulting in O(n^2) time complexity, which is inefficient for large arrays.

Core Observation

Because the array is sorted, the sum of two numbers can be compared to the target to decide which pointer to move. If the sum is too large, moving the right pointer left decreases the sum; if too small, moving the left pointer right increases the sum.

Path to Optimal

The sorted property enables a two-pointer approach. Initialize one pointer at the start and one at the end. Calculate the sum. If sum > target, move the right pointer left to reduce sum. If sum < target, move the left pointer right to increase sum. Repeat until the sum equals the target. This reduces time complexity to O(n).

Optimal Approach

Use two pointers, left and right, starting at the array's ends. In each iteration, compute the sum of numbers[left] and numbers[right]. If sum equals target, return the 1-based indices. If sum is greater than target, decrement right pointer. If sum is less than target, increment left pointer. This guarantees finding the solution in a single pass with O(n) time and O(1) space.

Time

O(n)

Each pointer moves at most n times, resulting in a single linear pass through the array.

Space

O(1)

Only two pointer variables and a few auxiliary variables are used, independent of input size.

Pattern Spotlight

Two Pointers (Greedy Contraction)

The logic of any optimal Two Pointers solution lies in finding the condition that allows you to permanently discard one end of the search space by moving the pointer that is the current 'limiting factor' to the solution.

Solution

1class Solution:
2 def twoSum(self, numbers: list[int], target: int) -> list[int]:
3 l, r = 0, len(numbers) - 1
4
5 while l < r:
6 current_sum = numbers[l] + numbers[r]
7
8 if current_sum > target:
9 r -= 1
10 elif current_sum < target:
11 l += 1
12 else:
13 return [l + 1, r + 1]

Step-by-Step Solution

1

Initialize Left and Right Pointers at Array Boundaries

3l, r = 0, len(numbers) - 1

Objective

To set up two pointers at the start and end of the sorted array to begin the search for the target sum.

Key Insight

Starting pointers at the extremes leverages the sorted order to evaluate the largest and smallest elements first, enabling a greedy contraction of the search space based on the sum comparison with the target.

Interview Quick-Check

Core Logic

Initializing pointers at the array boundaries sets the widest possible range to evaluate sums, enabling efficient contraction.

State & Boundaries

Pointers must be valid indices within the array, starting at 0 and len(numbers) - 1.

2

Iteratively Adjust Pointers Based on Sum Comparison

5while l < r:
6 current_sum = numbers[l] + numbers[r]
8 if current_sum > target:
9 r -= 1
10 elif current_sum < target:
11 l += 1

Objective

To move pointers inward based on whether the current sum is greater or less than the target, narrowing down to the correct pair.

Key Insight

Because the array is sorted, if the sum is too large, moving the right pointer left decreases the sum; if too small, moving the left pointer right increases the sum. This greedy adjustment ensures no valid pairs are skipped and the search space shrinks each iteration.

Interview Quick-Check

Core Logic

The sum comparison guides pointer movement: decrement right if sum too large, increment left if sum too small, ensuring convergence to the target sum.

State & Boundaries

The loop continues while left pointer is less than right pointer, ensuring distinct elements.

Common Pitfalls & Bugs

Failing to update pointers correctly or using <= instead of < in the loop condition can cause infinite loops or incorrect results.

3

Return 1-Based Indices of the Found Pair

12else:
13 return [l + 1, r + 1]

Objective

To return the indices of the two numbers that sum to the target, adjusted for 1-based indexing as required by the problem.

Key Insight

The problem specifies 1-based indexing, so the zero-based pointers must be incremented by one before returning. Returning immediately upon finding the pair ensures optimal time complexity.

Interview Quick-Check

Core Logic

Returning the adjusted indices immediately upon finding the target sum terminates the search efficiently.

State & Boundaries

Indices must satisfy 1 <= index1 < index2 <= numbers.length.

Line Analysis

This solution has 2 Critical lines interviewers watch for.

Line 3 Critical
l, r = 0, len(numbers) - 1

Initialize left and right pointers at the start and end of the array.

Setting pointers at the array boundaries leverages the sorted order to evaluate the largest and smallest elements first, enabling efficient contraction of the search space.

Line 5 Critical
while l < r:

Begin a loop that continues while left pointer is less than right pointer.

The loop condition ensures that the two pointers do not cross, maintaining the invariant that the pointers reference distinct elements.

Line 6 Standard
current_sum = numbers[l] + numbers[r]

Calculate the sum of the elements at the left and right pointers.

Computing the current sum is essential to decide how to adjust the pointers to approach the target.

Line 8 Standard
if current_sum > target:

Check if the current sum is greater than the target.

If the sum is too large, the right pointer must move left to reduce the sum, exploiting the sorted order.

Line 9 Standard
r -= 1

Move the right pointer one step to the left.

Decrementing the right pointer reduces the sum by selecting a smaller number, moving closer to the target.

Line 10 Standard
elif current_sum < target:

Check if the current sum is less than the target.

If the sum is too small, the left pointer must move right to increase the sum.

Line 11 Standard
l += 1

Move the left pointer one step to the right.

Incrementing the left pointer increases the sum by selecting a larger number, moving closer to the target.

Line 12 Standard
else:

Return the 1-based indices of the two numbers that sum to the target.

Returning immediately upon finding the correct pair ensures optimal time complexity and satisfies the problem's 1-based indexing requirement.

Line 13 Standard
return [l + 1, r + 1]

Adjust zero-based indices to 1-based before returning.

The problem specifies 1-based indexing, so adding one to each pointer aligns the output with the problem constraints.

Test Your Understanding

Why does moving the pointer at the side that causes the sum to be too large or too small guarantee finding the solution without missing any valid pairs?

Because the array is sorted, moving the pointer at the side that causes the sum to be off adjusts the sum in the correct direction without skipping any potential valid pairs, ensuring all possibilities are explored efficiently.

Related Problems

Two Pointers pattern

Don't just read it. Drill it.

Reconstruct Two Sum II - Input Array Is Sorted from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Two Sum II - Input Array Is Sorted drill

or drill a free problem