两数之和

1091 字
5 分钟
两数之和

题目链接:1. 两数之和 - 力扣(LeetCode)

  • 难度:简单
  • 标签:数组,哈希表

题目描述#

Note

原题说明: 给定一个整数数组 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]

提示#

  • 2nums.length1042 \le nums.length \le 10^4
  • 109nums[i]109-10^9 \le nums[i] \le 10^9
  • 109target109-10^9 \le target \le 10^9
  • 只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n2)O(n^2) 的算法吗?



方案一:暴力解法#

首先,我想出来的是一个非常直观的办法:两层嵌套循环,逐次遍历所有可能的组合,找到目标的两个元素后返回。

下面是我写出来的第一版代码(存在不少典型错误)

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
cin >> nums ; // 错误 1
cin >> target ; // 错误 1
for (int i = 0; i < sizeof(nums); i++) // 错误 2
{
for (int j = 0; j < sizeof(nums); i++) // 错误 3
{
return nums[j]; // 错误 4
}
if(nums[j]+nums[i] == target)
return [nums[i],nums[j]]; // 错误 5
}
cout << nums[i],nums[j] <<endl; // 错误 6
}
};

错误分析与改进#

  1. 输入方式:LeetCode 不需要手动 cin 输入,numstarget 是函数参数。
  2. 元素数量获取sizeof(nums) 返回的是 vector 对象本身的大小,应使用 nums.size() 获取元素个数。
  3. 循环变量控制:内层循环的更新应该是 j++ 而不是 i++
  4. 提前返回return nums[j] 会在找到结果前提前退出函数。
  5. 返回值语法:C++ 中返回 vector 应使用花括号 {}(如 return {i, j})。
  6. 输出与逗号表达式cout 不支持此类写法,且 LeetCode 不需要输出结果。
  7. 重复使用元素:内层循环 j 应该从 i + 1 开始,以避免“同一个元素被使用两次”的问题。

优化的暴力解法#

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0; i < nums.size(); i++) {
for (int j = i + 1; j < nums.size(); j++) {
if(nums[j] + nums[i] == target) {
return {i, j};
}
}
}
return {};
}
};

运行结果:

  • 执行用时:95ms
  • 消耗内存:13.70MB

复杂度分析#

  • 时间复杂度O(n2)O(n^2)。其中 nn 是数组中的元素数量。最坏情况下,我们需要遍历每一对可能的组合。
  • 空间复杂度O(1)O(1)。我们只使用了常数级的额外空间。

方案二:哈希表优化(推荐)#

为了进一步提升效率,我们可以利用哈希表(unordered_map)

核心思路: 通过“空间换时间”,在遍历数组时,将已经访问过的数值及其下标存入哈希表。对于当前数值,直接在哈希表中匹配所需的“补数”。

优化版源码#

#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> numToIndex; // 创建哈希表:数值 -> 下标
for (int i = 0; i < nums.size(); ++i) { // 只需要遍历一次
int complement = target - nums[i]; // 计算满足条件的另一个数
if (numToIndex.count(complement)) { // 在 O(1) 内查找补数是否存在
return {numToIndex[complement], i};
}
numToIndex[nums[i]] = i; // 将当前数值存入,供后续查用
}
return {};
}
};

运行结果:

  • 执行用时:4ms
  • 消耗内存:14.57MB

复杂度分析#

  • 时间复杂度O(n)O(n)。我们只需遍历一次包含 nn 个元素的数组,哈希表的查询操作平均时间复杂度为 O(1)O(1)
  • 空间复杂度O(n)O(n)。主要取决于哈希表的开销,我们需要在哈希表中存储最多 nn 个元素。

关键点总结#

  • unordered_map:查找平均复杂度为 O(1)
  • 时间复杂度:从 O(n²) 降至 O(n)
  • 空间复杂度:为 O(n),用于维护哈希表。

结语#

  • 对于初学者,暴力解法是训练思维的第一步,但了解空间换时间的哈希思想是进阶的关键。
  • 注意:最后返回的是下标,而不是数组元素本身。
Tip

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

两数之和
https://firefly-7a0.pages.dev/posts/leetcode_notes/1two-sum/
作者
lonelystar
发布于
2025-09-27
许可协议
CC BY-NC-SA 4.0
最后更新于 2025-09-27,距今已过 214 天

部分内容可能已过时

评论区

Profile Image of the Author
LonelyStar
Hello, I'm LonelyStar.
公告
欢迎来到我的博客!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
119
分类
11
标签
346
总字数
226,548
运行时长
0
最后活动
0 天前

目录