[東哥的leetcode刷題日記] leetcode 167 :Two Sum II - Input array is sorted

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)的解法最優,能夠充分利用有序數組的條件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章