L1 两数之和
题目链接
https://leetcode.cn/problems/two-sum/description/
题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例
示例 1
输入: nums = [2,7,11,15], target = 9
输出: [0,1]
解释: 因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2
输入: nums = [3,2,4], target = 6
输出: [1,2]
示例 3
输入: nums = [3,3], target = 6
输出: [0,1]
提示
- 只会存在一个有效答案
题解
题目理解起来不难:遍历每个数,记为 now,然后看 target - now 有没有出现过,出现的话就找到结果了,直接返回即可。
最简单直接的办法就是双重循环暴力求解,但是看题目数据范围,这样大概率会超时,因此需要在此基础上找到一个更优的解法。
C++ 的 unordered_map 很适合这种情况,它是 C++11 之后提供的哈希表容器,无序存储、键唯一、查找平均 O(1),其常见用法如下表:
| 功能 | 示例代码 | 备注 |
|---|---|---|
| 创建 | unordered_map<int,string> mp; | 空哈希表 |
| 添加 / 修改 | mp[1] = "张三"; | 存在就覆盖,不存在新建 |
| 安全查找 key 是否存在 | mp.count(1) | 返回 0 不存在 / 1 存在 |
| 读取数值 | mp.at(1) | 找不到直接报错,不会自动新建 |
| 迭代器查找 | auto it = mp.find(1) | it != mp.end() 代表找到 |
| 删除 | mp.erase(1) | 按键删除 |
| 清空 | mp.clear() | - |
| 元素个数 | mp.size() | - |
借助 unordered_map,代码实现如下:
#include <bits/stdc++.h>
using namespace std;
class Solution
{
public:
vector<int> twoSum(vector<int>& nums, int target)
{
unordered_map<int,int> mp; // 创建哈希表
for(int i = 0; i < nums.size(); i++)
{
int now = nums[i]; // 当前值
int goal = target - now; // 当前值对应的目标值,也就是要找的值
// 注意:在这里为了方便查找使用,把数组中的元素当做键,把数组下标当做值
if(mp.count(goal)) // 找到键为 goal 的记录
{
return {mp.at(goal),i};
}
else // 没有找到键为 goal 的记录,需要把当前元素放入
{
mp[now] = i; // 记录键为当前元素,值为数组下标
// 注意:如果键已存在,会覆盖旧值。本题中由于找到答案即返回,不会出现重复键的情况。
}
}
return {}; // 理论上说是不会到这一步的,因为题目规定答案存在,这里返回是语法要求
}
};
// 注意:以下为自行补充的测试示例
int main()
{
Solution test;
vector<int> nums = {2,7,11,15};
int target = 9;
vector<int> res = test.twoSum(nums, target);
// 输出结果
for(int x : res) // 依次取出 res 里面的每一个整数,赋值给变量 x,循环执行
{
cout << x << " ";
}
cout << endl;
return 0;
}力扣平台只需提交 class Solution,可以在线编写并且进行评测,但如果想要使用自己的开发工具进行编写,就需要补充完整的测评代码了。上面的示例代码中含有 main(),之后的代码也可以仿照这种样式自行构造输入输出,写死测试示例或者实时读入测试数据都是可以的。后续的博客中只会放置 class Solution 部分的代码,完整的代码会整理至个人 GitHub 仓库:C571467648/blog,如有需要可以自行下载,别忘了顺手 star 一下哦~
言归正传,现在简单讲解一下代码:
我们用变量 int now = nums[i] 表示当前正在处理的数组元素,用 int goal = target - now 表示当前元素所需要配对的"目标元素",后续的任务就变成了这个目标元素 goal 是否出现过。如果 goal 在之前出现过,那么就找到了答案直接返回即可,否则把当前的元素记录到哈希表中,等待后续被查找。
特别需要注意的是,为了方便查找使用,把数组中的元素当做键,把数组下标当做值,千万不能弄混了!
mp.count(goal) 配合 mp.at(goal) 需要两次独立的查找操作。而 mp.find(goal) 一次查找就能同时得知存在性和值,代码更简洁、效率也略高一些。不过在实际运行中,这种差异通常很小,使用哪种写法都可以。(关于迭代器这部分可以参考 C++ 专栏的 STL,如果还没有更新,也可以先自行搜索学习,这里不过多讲解)
class Solution
{
public:
vector<int> twoSum(vector<int>& nums, int target)
{
unordered_map<int,int> mp;
for(int i = 0; i < nums.size(); i++)
{
int now = nums[i];
int goal = target - now;
auto it = mp.find(goal);
if(it != mp.end())
return {it->second,i};
else
mp[now] = i;
}
return {};
}
};这里通过 find(goal) 直接获取指向 goal 的迭代器(如果没有找到,会指向 mp.end()),然后通过 it->second 直接获取值。(扩展一下:it->first 可以获取键,即数组元素的值)

本题讲解就到这里啦,欢迎交流讨论~
本文内容主要来自个人学习与实践总结,受限于个人技术水平,难免存在理解不准确或表述疏漏等错误。 若您发现问题,或愿意就相关内容进一步交流,欢迎通过邮箱 571467648@qq.com 与我联系。感谢您的阅读与指正。