力扣1. 两数之和

题目来源(力扣):
https://leetcode.cn/problems/two-sum/description/

题目描述:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值target的那 两个 整数,并返回它们的数组下标。
保证只会出现一个答案

基本思路:
就是已知a+b=c,求数组中是否存在a和b使得式子成立。
先对问题简化:
如果假设数组nums[]中各个数字都是不同的,那么直接对数组构建哈希表m(这里用std::unordered_map),m存储的是每个数的下标(从1开始而非从0开始,便于判断真假)
之后再扫一遍数组nums[],对于nums[i],如果val=c-nums[i]在哈希表中,则返回[i,m[val]-1] (m[val]-1,因为vector从下标0开始)

简化代码(无法通过所有样例)

class Solution
{
public:
    vector<int> twoSum(vector<int> &nums, int target)
    {
        unordered_map<int, int> m;
        vector<int> ans;
        for (int i = 0; i < nums.size(); i++)  //直接对数组构建哈希表m
        {
            m[nums[i]] = i + 1;  //m存储的是每个数的下标 ,从1开始
        }
        for (int i = 0; i < nums.size(); i++)  
        {
            int val = target - nums[i];  //nums[i]在数组内
            if (m[val])  //如果val也在数组内,则找到答案
            {
                ans.push_back(m[val] - 1);
                ans.push_back(i);
                break;
            }
        }
        return ans;
    }
};

错误原因

首先,原数组中,同一个数可以出现多次,例如[3,3,4],则返回答案应该为[0,1](或者[1,0]),而非[0,0]或[1,1]

其次,当数组中出现某数为目标c的一半时,不能重复取它,即题目中要求的“请你在该数组中找出和为目标值target的那 两个 整数”,
例如[1,3,7,9,5],而目标值为14,则返回答案应该为[3,4](或者[4,3]),而非[2,2]

一个解决方法就是,边建表边判断
具体而言,对于当前要进入到哈希表m中的nums[i],考虑val=target-nums[i],如果val已经哈希表中,则返回[i,m[val]-1]
否则,将nums[i]加入到哈希表m中,即m[nums[i]]=i+1;

会发现和简化的思路完全一致(甚至代码也高度相似),只是将“先建表后判断”改为了“边建表边判断”,就能避免出现各种问题了~(想想为什么)

完整代码如下

class Solution
{
public:
    vector<int> twoSum(vector<int> &nums, int target)
    {
        unordered_map<int, int> m;
        vector<int> ans;
        for (int i = 0; i < nums.size(); i++)
        {  //nums[i]在数组内
            int val = target - nums[i];  //如果val也在数组内
            if (m[val])  //则找打答案
            {
                ans.push_back(m[val] - 1);
                ans.push_back(i);
                break;
            }
            m[nums[i]] = i + 1;  //将nums[i]加入到m中
        }
        return ans;
    }
};

《代码随想录》写法:

写得更加简洁,但是思路完全一致
利用find,从而无需对下标进行+1和-1操作

class Solution
{
public:
    vector<int> twoSum(vector<int> &nums, int target)
    {
        unordered_map<int, int> m;
        for (int i = 0; i < nums.size(); i++)
        {
            auto iter = m.find(target - nums[i]);
            if (iter != m.end())
            {
                return {iter->second, i}; // 等价于 return {m[nums[target-nums[i]]], i}
            }
            m.insert(pair<int, int>(nums[i], i)); // 等价于 m[nums[i]]=i;
        }
        return {};
    }
};

时间复杂度

这里使用std::unordered_map ,时间复杂度为O(n),其中n为数组大小
如果采用普通的std::map ,则时间复杂度为O(nlogn),n为数组大小

posted @ 2024-10-22 11:10  HB_Computer  阅读(31)  评论(0)    收藏  举报