[东哥的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)的解法最优,能够充分利用有序数组的条件。

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