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. Let these two numbers be numbers[index1]
and numbers[index2]
where 1 <= index1 < index2 <= numbers.length
.
Return the indices of the two numbers, index1
and index2
, added by one as an integer array [index1, index2]
of length 2.
The tests are generated such that there is exactly one solution. You may not use the same element twice.
Your solution must use only constant extra space.
Example 1:
Input: numbers = [2,7,11,15], target = 9 Output: [1,2] Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2].
Example 2:
Input: numbers = [2,3,4], target = 6 Output: [1,3] Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 = 3. We return [1, 3].
Example 3:
Input: numbers = [-1,0], target = -1 Output: [1,2] Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2 = 2. We return [1, 2].
Constraints:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers
is sorted in non-decreasing order.-1000 <= target <= 1000
This problem asks to find two numbers within a sorted array that add up to a specific target. The solution must use only constant extra space.
This approach iterates through the array. For each number, it uses binary search to check if the complement (target - number) exists in the remaining portion of the array.
Algorithm:
for
loop.numbers[i]
, calculate its complement complement = target - numbers[i]
.numbers[i+1:]
to find the complement
. bisect_left
(or lower_bound
in C++) is efficient for this.j
within the subarray, return [i+1, j+1]
(indices are 1-based).Time Complexity: O(n log n). The outer loop iterates n times, and the binary search takes O(log n) time in each iteration.
Space Complexity: O(1). The algorithm uses only a few variables to store indices and the complement.
This approach leverages the sorted nature of the input array. It uses two pointers, one at the beginning and one at the end of the array, and moves them towards the middle based on the sum of the numbers they point to.
Algorithm:
left
at the beginning (index 0) and right
at the end (index n-1) of the array.sum = numbers[left] + numbers[right]
.sum == target
, return [left + 1, right + 1]
(1-based indices).sum < target
, increment left
to consider a larger number.sum > target
, decrement right
to consider a smaller number.left
and right
cross each other (left >= right
).Time Complexity: O(n). The two pointers move towards the middle, resulting in at most n comparisons.
Space Complexity: O(1). Only a few variables are used.
Here's how the two approaches are implemented in various programming languages:
(Note: The following code snippets omit error handling for brevity. Production code should include checks to handle edge cases like empty input arrays or cases where no solution exists.)
import bisect
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
n = len(numbers)
for i in range(n):
complement = target - numbers[i]
j = bisect.bisect_left(numbers, complement, i + 1)
if j < n and numbers[j] == complement:
return [i + 1, j + 1]
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left, right = 0, len(numbers) - 1
while left < right:
current_sum = numbers[left] + numbers[right]
if current_sum == target:
return [left + 1, right + 1]
elif current_sum < target:
left += 1
else:
right -= 1
Similar code can be written in Java, C++, JavaScript, and other languages using the same core logic for both approaches. The two-pointer approach is generally preferred due to its better time complexity.