1. Two Sum

题目链接1. Two Sum

思考过程:

最容易想到的思路是直接遍历每个元素,然后用target 减去这个元素得到一个数N,接着再遍历整个数组去寻找看N在不在数组中。这样做的时间复杂度为O(n^2)

n^2的复杂度来至于2个方面,第一,是遍历每个元素复杂度O(n),第二是对于每个元素与target相减得到的数N都需要复杂度为O(n)的查找操作,两者是相乘关系,所以优化带来的效益是一样的。
很显然,第一点是无法优化的,因为我们至少需要遍历一遍所有元素,所以关注点应该是第二点,即在获得某个数的前提下去数组中查找该数是否存在,对于这题而言,如果该数存在,还需要知道其下标。

问题转变成,如何快速在数组中查找某个元素的下标,并且时间复杂度要低于O(n), 我们立刻想到二分查找,但是二分查找的前提是数组有序,题目未指明该前提,故不可用。
另外一个思路是hash,对于整数而言,如果存在数据范围,可直接用其作为下标进行hash,但是题目未明确说明数据范围,故不可用,即O(1) hash不可用。
进而求其次考虑O(logn) hash,立刻想到用map,C++中map的查找复杂度即O(logn)。
这样总复杂度降低为O(nlogn)

可以首先遍历数组,建立其map<数,下标 + 1> ,下标 + 1是为了用0表示数不存在
然后遍历数组,查找target - num在map中是否存在, 如果存在则,则答案找到。

细节思考:

  1. 题目并没有明确说明不存在重复数,所以要考虑重复数,假设存在重复数,那么有两种情况,第一种就是重复数是答案,那么我们可以断定,只有当重复数是target/2的时候才有可能,因为如果是重复数与另外一个数组成了答案,那么必然存在2个以上的答案组,这个情况题目确定说了不可能,所以我们当我们发现重复数的时候,只需要判断是否是target/2, 如果不是,则该数的所有副本都不可能是答案,所以关于重复数的其他所有问题都无需考虑。
  2. 思路中的两步可以合成一步,即一边建立map,一边遍历数组。

参考代码:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        map<int, int> nums_map;
        vector<int> ans;
        for (int i = 0; i < nums.size(); i++){

            //只有这种情况会出现两个相同的数且答案中含有这个数
            if (nums_map[nums[i]] != 0 && target - nums[i] == nums[i]){
                ans.push_back(nums_map[nums[i]] - 1);
                ans.push_back(i);
                break;
            }
            //试着寻找答案
            nums_map[nums[i]] = i + 1;
            if (nums_map[target - nums[i]] != 0 && nums_map[target - nums[i]] != i + 1){
                ans.push_back(nums_map[target - nums[i]] - 1);
                ans.push_back(i);
                break;
            }
        }
        return ans;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值