leetcode 167 两数之和Ⅱ (双指针,哈希表实现)

题目描述:
给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,
请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数
分别是 numbers[index1] 和 numbers[index2] ,则 
1 <= index1 < index2 <= numbers.length 。
示例:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。
算法思想:
双指针:

如果是朴素思想,则是两层枚举,分别枚举 i,j 其中i的范围是: 0~n-1, j 的范围是:i 到 n-1。
优化的方法是找到枚举的冗余部分将其去除。

优化的策略是:
1、固定右端点 i, 看左端点 j 的取值范围,如果左端点取值范围是一个前缀,可以使用“前缀和”维护前缀信息。
2、移动一个端点,看另一个端点单调移动,像一个“滑动窗口”,此时可以考虑“双指针扫描”

这里链表是非递减的,枚举 i,考虑消掉朴素算法里面一层j循环,移动 i 可以看到,由于numbers[i] + numbers[j] == target, i 右移导致numbers[i]增大,则 j 只能向左边移动,才能满足 numbers[i] + numbers[j] == target.

c++代码实现:
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int j = numbers.size() - 1; // j从右边枚举
        for(int i = 0; i < numbers.size()-1; i++){ // 由于i,j不能重复所以i的范围是 0 ~ n-1
            while(i < j && numbers[i] + numbers[j] > target)  j --; // 满足条件则向左移动 j
            if(i < j && numbers[i] + numbers[j] == target)
                return {i + 1, j + 1}; // 下标从1开始计算
        }
        return {};
    }
};
哈希表:

朴素思想枚举 i , j 每次枚举 i 需要O(n)的时间枚举查找j,为了优化j的查找时间降到O(1),可以考虑开一个哈希表,由于哈希表的插入,查找都是O(1)的,就可以起到优化j查找的目的了。考虑到关注的是numbers[i] + numbers[j] == target,所以哈希表的键应该是numbers[i],值因该是对应的索引 i,这样在枚举 i的过程中,可以在哈希表中查找有没有存在满足 target - numbers[i]的值,如果存在,则返回对应的值与i组成答案即可。枚举过程中将numbers[i]与其对应的索引 i 插入哈希表中。

c++代码实现:
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        for(int i = 0; i < numbers.size();i ++){
            auto x = target - numbers[i];
            if(hash.count(x))
                return {hash[x] + 1, i + 1};
            hash[numbers[i]] = i;
        }
        return {};
    }
private:
    unordered_map<int,int>hash;
};
时间复杂度:

朴素方法枚举 i, j 两重循环时间复杂度是 O(n^2);
双指针方法枚举 i, 平均时间复杂度是O(n);
哈希表方法时间复杂度:O(n),空间复杂度:O(n).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值