leetcode 167 :Two Sum II - Input array is sorted
題目鏈接: 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)的解法最優,能夠充分利用有序數組的條件。