Two Sum II - Input Array Is Sorted
The sorted property guarantees that pointer movements have monotonic effects on the sum. This transforms a search problem into an $O(1)$ elimination problem.
Pattern Summary
This problem uses the [Two Pointers] pattern.
- Recognition: Finding a pair of elements that sum to a target in a sorted array.
- Core Invariant: If
nums[left] + nums[right] < target, no element to the left ofrightcan form a valid pair withleftbecause the array is sorted. Theleftcandidate is permanently dead. - Transformation: Replace $O(n \log n)$ binary searches or $O(n)$ hash map space with an $O(1)$ amortized state space elimination.
$\rightarrow$ Read the full theoretical foundation: [Two Pointers]
Real-World Analogues
Financial Matching
Budget Allocation
Given a sorted list of component costs, find two components that exactly exhaust a budget. Searching with opposing pointers allows an embedded system to find the pair without allocating a hash table in constrained memory.
Interview Abstraction
LeetCode 167 asks: given a 1-indexed array of integers numbers sorted in non-decreasing order, return the indices of the two numbers that add up to target using only $O(1)$ extra space.
Why This Problem Matters
This problem bridges the gap between searching and structural invariants. It teaches you how a sorted property enables $O(1)$ search space reduction from two ends.
| What This Problem Teaches | What It Does NOT Teach |
|---|---|
| ✓ Search space reduction | ✗ Handling duplicates (see 3Sum) |
| ✓ Monotonic pointer effects | ✗ Unsorted array hashing (see Two Sum) |
| ✓ $O(1)$ space optimization | ✗ Sliding windows (see Continuous Subarrays) |
Recognition
Reach for this pattern when:
- ✓ The input is a sequence that is already sorted.
- ✓ You are looking for pairs that satisfy a mathematical relation (sum, difference, product).
- ✓ The problem explicitly restricts auxiliary space to $O(1)$.
The Mental Shift
Naive Thought → "For each number, binary search the rest of the array for the complement."
Correct Thought → "The sorted order tells me exactly which pointer to move to adjust the sum."
If the sum is too small, you must increase it. Because the right pointer is already at the maximum possible remaining value, the only way to increase the sum is to increment the left pointer.
Solution Evolution
| Approach | Time | Space | Core Idea | Why It Fails / Bottleneck |
|---|---|---|---|---|
| 1. Hash Map | $O(n)$ | $O(n)$ | Store complements in a map | Fails the $O(1)$ space requirement. |
| 2. Binary Search | $O(n \log n)$ | $O(1)$ | For x, binary search target - x | Sub-optimal time complexity. |
| 3. Opposing Pointers | $O(n)$ | $O(1)$ | Adjust pointers based on sum | Optimal; strictly constant space and single pass. |
Why This Beats Binary Search
Binary search answers: “Where is the complement in the remaining array?”
The two-pointer approach answers: “Can we eliminate an entire row/column of the search space in $O(1)$?”By moving one pointer, we implicitly eliminate all combinations involving that pointer, dropping the factor from $O(\log n)$ to amortized $O(1)$.
From Pattern → Code
The opposing pointers pattern maps to simple policies:
# 1. SUM: Compute current state safely
if target - numbers[left] > numbers[right]:
# 2. INCREASE: Sum is too small
left += 1
elif target - numbers[left] < numbers[right]:
# 3. DECREASE: Sum is too large
right -= 1
else:
# 4. MATCH: Return 1-indexed positions
return [left + 1, right + 1]
Optimal Solution
from typing import List
def two_sum(numbers: List[int], target: int) -> List[int]:
left, right = 0, len(numbers) - 1
out = []
while left < right:
# Safe comparison avoiding integer overflow
if target - numbers[left] > numbers[right]:
left += 1
elif target - numbers[left] < numbers[right]:
right -= 1
else:
out.append(left + 1)
out.append(right + 1)
return out
return out
Visual Walkthrough
Tracing numbers = [2, 7, 11, 15], target = 9.
Complexity Analysis
| Metric | Complexity | Rationale |
|---|---|---|
| Time | $O(n)$ | The left and right pointers converge exactly once. Total operations $\le n$. |
| Space | $O(1)$ | Only two integer pointers and an output array are allocated. |
Edge Cases
| Dimension | Test Case | Expected Behavior |
|---|---|---|
| Negative Numbers | nums = [-10, -8, -2, 7, 8, 10], tgt = -1 | Correctly computes -8 + 7 = -1 returning [2, 4]. |
| Duplicate Values | nums = [1, 2, 4, 4, 9], tgt = 8 | Safe comparisons correctly match 4 + 4 returning [3, 4]. |
Common Mistakes
- ❌ Using Extra Space: Falling back to a Hash Map approach which violates the $O(1)$ auxiliary space constraint.
- ❌ Integer Overflow: In languages with bounded integers, computing
numbers[left] + numbers[right]can overflow. The structuretarget - numbers[left] > numbers[right]guarantees safety. - ❌ 0-Indexing: Forgetting that the problem explicitly requests 1-indexed output format.
Problem Progression
Mastering this problem enables you to solve a progression of harder variations:
- 3Sum (Medium): Wrapping Two Sum II in an outer loop to find triplets.
- 4Sum (Medium): Extending to quadruplets with early termination.
- Container With Most Water (Medium): Modifying the pointer elimination logic for area instead of sum.
Principal Lens
If you remember one thing: A sorted array transforms pair finding from a $O(N)$ memory hashing task into an $O(1)$ memory search space reduction task. If the sum is too small, your only valid move is to advance the left pointer.