Two Sum II - Input Array Is Sorted
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.
- 2 <= numbers.length <= 3 × 10^4
- Array is sorted in non-decreasing order
- Exactly one solution exists
- Must use O(1) extra space
numbers = [2,7,11,15], target = 9[1,2]numbers = [2,3,4], target = 6[1,3]numbers = [-3,-1,0,2,5], target = -1[2,3]When we have a sorted dataset, we have a massive advantage: information about one element tells us exactly where to look for others. Instead of guessing, we can make informed decisions based on the current sum.
The most basic approach is to pick every possible first number and then scan the rest of the array to see if its partner exists. This approach completely ignores the fact that the array is sorted. It is highly inefficient because it re-scans the same numbers over and over, leading to quadratic time complexity.
# Brute force: nested loops
def brute_force(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i + 1, j + 1]Since the array is sorted, we could improve our search. For every number nums[i], we could perform a binary search to find target - nums[i] in the remaining part of the array. While this improves time complexity to O(N log N), it still feels clunky because we are performing a search from scratch for every single element, ignoring the relationship between adjacent numbers.
Because the array is sorted, the data has a "directional bias"—smaller values are on the left, and larger values are on the right. This allows us to use two pointers to "squeeze" the search space from both ends, effectively turning a multi-step search into a single, O(N) pass. We place one pointer at the start (Left) and one at the end (Right), acting as a pressure valve to adjust our sum toward the target.
- If the current sum is too small, we need a larger value. Moving the Left pointer to the right increases the sum.
- If the current sum is too large, we need a smaller value. Moving the Right pointer to the left decreases the sum.
This approach is optimal because every movement eliminates exactly one value that we now know cannot be part of the solution.
# Optimal: two pointers
def two_pointers(nums, target):
left, right = 0, len(nums) - 1
while left < right:
current_sum = nums[left] + nums[right]
if current_sum == target:
return [left + 1, right + 1]
elif current_sum < target:
left += 1
else:
right -= 1Two Sum II Visualization
Converging pointers on a sorted array
Crucial Concept
- Monotonic Sum: Moving 'Left' right increases sum. Moving 'Right' left decreases sum.
- Deterministic: At any step, we know exactly which pointer to move based on the sum comparison.
- No Backtracking: Pointers only move in one direction (inward), guaranteeing O(N).
Pattern Recognition
Whenever you need to find a pair in a sorted array, always consider the Two Pointer approach. It almost always beats the O(N) hash map approach in space complexity (O(1) vs O(N)).