leetcode 167. 两数之和 II - 输入有序数组
大约 2 分钟
给你一个下标从 1 开始的整数数组 numbers
,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target
的两个数。如果设这两个数分别是 numbers[index1]
和 numbers[index2]
,则 1 <= index1 < index2 <= numbers.length
。
以长度为 2 的整数数组 [index1, index2]
的形式返回这两个整数的下标 index1
和 index2
。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
你所设计的解决方案必须只使用常量级的额外空间。
方法一:哈希
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
unordered_map<int, int> hashMap;
for(int i = 0; i < numbers.size(); ++i) {
if(hashMap.count(target - numbers[i])) {
return {hashMap[target - numbers[i]] + 1,i + 1};
}
hashMap[numbers[i]] = i;
}
return {};
}
};
- 一般用于
- 时间复杂度O(n) 空间复杂度O(n)
方法二:二分查找
- 对有序数组 可以使用二分查找法 查找target - nums.at(i)
- 时间复杂度O(nlogn) 空间复杂度O(1)
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
for(int i = 0; i < numbers.size(); ++i) {
int ret = binarySearch(numbers, i + 1, numbers.size() - 1 , target - numbers[i]);
if(ret > -1) {
return {i + 1, ret + 1};
}
}
return {-1, -1};
}
int binarySearch(vector<int>& nums,int left, int right, int target) { //左闭右闭
if(left < 0 || right > nums.size() || left > right) {
return -1;
}
while(left <= right) {
int middle = left + (right - left) / 2;
if(target > nums[middle]) {
left = middle + 1;
}
else if(target == nums[middle]) {//判断相等时一定要小心,不要写成赋值
return middle;
}
else {
right = middle - 1;
}
}
return -1;
}
};
方法三 :双指针法
- 时间复杂度:O(n),其中 n 是数组的长度。两个指针移动的总次数最多为 n 次。
- 空间复杂度:O(1)。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int left = 0;
int right = numbers.size() - 1;
if(numbers[left] > target && numbers[left] > 0) {
return {-1, -1};
}
while(left < right) {
while(left < right && numbers[left] + numbers[right] > target) {
--right;
}
while(left < right && numbers[left] + numbers[right] < target) {
++left;
}
if(numbers[left] + numbers[right] == target) {
return {left + 1, right + 1};
}
}
return {-1, -1};
}
};