给你一个下标从 1 开始的整数数组 numbers
,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target
的两个数。如果设这两个数分别是 numbers[index1]
和 numbers[index2]
,则 1 <= index1 < index2 <= numbers.length
。
以长度为 2 的整数数组 [index1, index2]
的形式返回这两个整数的下标 index1
和 index2
。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
示例 1:
输入:numbers = [2,7,11,15], target = 9 输出:[1,2] 解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
示例 2:
输入:numbers = [2,3,4], target = 6 输出:[1,3] 解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。
示例 3:
输入:numbers = [-1,0], target = -1 输出:[1,2] 解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers
按 非递减顺序 排列-1000 <= target <= 1000
- 仅存在一个有效答案
双指针法(Two-Pointer Technique):
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left = 0;
int right = numbers.size() - 1;
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum == target)
break;
if (sum < target)
left++;
else
right--;
}
return {left + 1, right + 1};
}
};
在这个问题中,由于数组已按非递减顺序排列,双指针法利用了数组的有序性,让我们可以在一个线性时间复杂度内找到满足条件的两个数的下标。
left
指针从数组的开头(最小值)开始,right
指针从数组的末尾(最大值)开始。通过不断调整这两个指针来逼近目标值 target
。
在每一步中,计算 numbers[left] + numbers[right]
的和。
- 如果和等于
target
:我们已经找到解[left + 1, right + 1]
(题目要求下标从 1 开始)。 - 如果和小于
target
:说明当前组合的和不够大。因为数组是有序的,增加left
指针使其指向更大的数有助于增大和,从而更接近target
。 - 如果和大于
target
:说明当前组合的和太大了。减小right
指针可以使其指向一个较小的数,从而减小和,更接近target
。
时间和空间效率:
- 双指针法通常在
O(n)
时间内完成操作,因为每个指针只朝一个方向单调地移动,且不会回头或在同一个位置重复计算。 - 空间复杂度是
O(1)
,因为只使用了常数额外空间,不需要额外的数据结构。
以 numbers = {2, 7, 11, 15}
,target = 9
为例:
-
初始化:
left = 0
(指向 2),right = 3
(指向 15)sum = numbers[left] + numbers[right] = 2 + 15 = 17 > target
,因为和太大,右指针左移。
-
更新指针:
left = 0
,right = 2
(指向 11)sum = 2 + 11 = 13 > target
,和仍然太大,右指针继续左移。
-
更新指针:
left = 0
,right = 1
(指向 7)sum = 2 + 7 = 9 == target
,找到符合条件的下标[1, 2]
(下标从 1 开始)。