问题描述:
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
注1:函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足
1
<
=
a
n
s
w
e
r
[
0
]
<
a
n
s
w
e
r
[
1
]
<
=
n
u
m
b
e
r
s
.
l
e
n
g
t
h
1 <= answer[0] < answer[1] <= numbers.length
1<=answer[0]<answer[1]<=numbers.length 。
注2:你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
思路分析与代码实现
方法一:二分法搜索
先固定第一个数,然后第二个数使用二分法来搜索。
代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int n = numbers.size();
for (int i = 0; i < n; i++) {
int low = i + 1;//第二个数保证在第一个数右边
int high = n-1;
while(low<=high) {
int mid = low + (high - low) / 2;
if(nums[i] = target - nums[mid])
return {i+1,mid+1};
else if (nums[i] < target - nums[mid]){
low = mid + 1;
}
else
high = mid - 1;
}
}
return {-1,-1};//没有满足条件的目标
}
};
- 复杂度分析
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),其中 n n n 是数组的长度。需要遍历数组一次确定第一个数,时间复杂度是 O ( n ) O(n) O(n),寻找第二个数使用二分查找,时间复杂度是 O ( l o g n ) O(logn) O(logn),因此总时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)。
空间复杂度: O ( 1 ) O(1) O(1)。
方法二:双指针
由于原数组是有序数组(升序),并且只有唯一解,那么可以使用两个指针,分别指向第一个元素
i
i
i和最后一个元素
j
j
j。当两个元素
n
u
m
b
e
r
s
[
i
]
+
n
u
m
b
e
r
s
[
j
]
numbers[i]+numbers[j]
numbers[i]+numbers[j]小于目标值时,代表着
n
u
m
b
e
r
s
[
i
]
numbers[i]
numbers[i]无法满足要求(太小),则
i
+
+
i++
i++。如果当两个元素
n
u
m
b
e
r
s
[
i
]
+
n
u
m
b
e
r
s
[
j
]
numbers[i]+numbers[j]
numbers[i]+numbers[j]大于目标值时,代表着
n
u
m
b
e
r
s
[
i
]
numbers[i]
numbers[i]无法满足要求(太大),则
j
+
+
j++
j++。当两个元素
n
u
m
b
e
r
s
[
i
]
+
n
u
m
b
e
r
s
[
j
]
numbers[i]+numbers[j]
numbers[i]+numbers[j]等于目标值时,输出
i
+
1
,
j
+
1
i+1,j+1
i+1,j+1。
其代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left= 0, right= numbers.size() - 1;
while(left <= right) {
int mid = left + (right - left) / 2;
if (numbers[left] < target - numbers[right]) {
left++;
}
else if(numbers[left] > target - numbers[right]) {
right--;
}
else {
return {left+1,right+1};
}
}
return {-1,-1};
}
};
- 复杂度分析
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组的长度。两个指针移动的总次数最多为 n n n 次。
空间复杂度: O ( 1 ) O(1) O(1)。
随写:
该题目有几个特点:
1、数组有序,这给双指针很大便利;
2、双指针一般是固定一个,移动另一个;
3、二分法一般用于有序数列,折半查找。