题目链接: https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/
难度: 简单
归类 : 数组操作, 二分查找, hashmap
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
示例 1:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
主要使用c++进行了解答,以及经典题解和尝试改进的最优/最简洁解法。
c++解法(hashmap法)
一次for循环,每次使用hashmap进行查找,找到即返回结果,否则存储hashmap,和第1题类似。
#python解法
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int len = numbers.size();
map<int, int> hashmap;
vector<int> res(2,0);
for(int i = 0; i < len; i++){
if(hashmap.find(target - numbers[i]) != hashmap.end()){
res[0] = hashmap[target - numbers[i]];
res[1] = i + 1;
return res;
}else{
hashmap[numbers[i]] = i + 1;
}
}
return res;
}
};
时间复杂度: O(N)
空间复杂度: O(1)
提交结果:
执行用时 :12 ms, 在所有 C++ 提交中击败了47.49%的用户
内存消耗 :9.8 MB, 在所有 C++ 提交中击败了6.90%的用户
c++解法(二分查找法)
因为数组是有序数组,因此可以使用双指针法,设置起始指针start=0,结尾指针end=len-1。假设二者之和刚好等于target,则返回结果;如果小于target,说明小了,则start+1;如果大于target,说明大了,则end-1;
#双指针法
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int len = numbers.size();
int start = 0;
int end = len - 1;
int curSum;
vector<int> res(2,0);
while(start < end){
curSum = numbers[start] + numbers[end];
if(curSum == target){
res[0] = start+1;
res[1] = end+1;
break;
}else if(curSum < target){
start++;
}else{
end--;
}
}
return res;
}
};
时间复杂度: O(logN)
空间复杂度: O(1)
提交结果:
执行用时 :8 ms, 在所有 C++ 提交中击败了81.29%的用户
内存消耗 :9.3 MB, 在所有 C++ 提交中击败了89.66%的用户
c++解法(定位中间+双指针)
定位到中间,再由里向两侧双指针扩散。但是和单独从两边向里的双指针法结果近似。
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> result={0,0};
int left,right,sum,i;
for(i=0;i<=numbers.size()-2;i++){
sum=numbers[i]+numbers[i+1];
if(sum==target){
result[0]=i+1;result[1]=i+2;
return result;
}
else if(sum<target) continue;
else break;
}
left=i;right=i+1;
sum=0;
while(left>=0&&right<=numbers.size()-1){
sum=numbers[left]+numbers[right];
if(sum==target){
result[0]=left+1;
result[1]=right+1;
return result;
}
else if(sum>target)
left--;
else
right++;
}
return result;
}
时间复杂度: O(log2N)
空间复杂度: O(1)
提交结果:
执行用时 :8 ms, 在所有 C++ 提交中击败了81.29%的用户
内存消耗 :9.3 MB, 在所有 C++ 提交中击败了89.66%的用户
python解法(二分查找+双指针)
将二分查找和双指针法相结合。每次双指针的左右更新都是通过二分查找来更改的,而不是简单的加1减1,能够大幅度减少时间。
class Solution:
def binary_search(self,num,tar,left,right,if_find_left):
while left<=right:
mid=(left+right)//2
if num[mid]<tar:
left=mid+1
elif num[mid]>tar:
right=mid-1
else:
return mid
return left if if_find_left else right
def twoSum(self, numbers: List[int], target: int) -> List[int]:
l,r=0,len(numbers)-1
while l<r:
sum_=numbers[l]+numbers[r]
if sum_<target:
l=self.binary_search(numbers,target-numbers[r],left=l+1,right=r,if_find_left=True)
elif sum_>target:
r=self.binary_search(numbers,target-numbers[l],left=l,right=r-1,if_find_left=False)
else:
return [l+1,r+1]
时间复杂度: O(log2N)
空间复杂度: O(1)
提交结果:
执行用时 :44 ms, 在所有 Python3 提交中击败了75.24%的用户
内存消耗 :14.4 MB, 在所有 Python3 提交中击败了6.25%的用户
本题使用上述时间复杂度为log(2N)的解法最优,能够充分利用有序数组的条件。