两数之和
1091 字
5 分钟
两数之和
- 难度:简单
- 标签:数组,哈希表
题目描述
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]
提示
- 只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 的算法吗?
方案一:暴力解法
首先,我想出来的是一个非常直观的办法:两层嵌套循环,逐次遍历所有可能的组合,找到目标的两个元素后返回。
下面是我写出来的第一版代码(存在不少典型错误):
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 }};错误分析与改进
- 输入方式:LeetCode 不需要手动
cin输入,nums和target是函数参数。 - 元素数量获取:
sizeof(nums)返回的是vector对象本身的大小,应使用nums.size()获取元素个数。 - 循环变量控制:内层循环的更新应该是
j++而不是i++。 - 提前返回:
return nums[j]会在找到结果前提前退出函数。 - 返回值语法:C++ 中返回
vector应使用花括号{}(如return {i, j})。 - 输出与逗号表达式:
cout不支持此类写法,且 LeetCode 不需要输出结果。 - 重复使用元素:内层循环
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
复杂度分析
- 时间复杂度:。其中 是数组中的元素数量。最坏情况下,我们需要遍历每一对可能的组合。
- 空间复杂度:。我们只使用了常数级的额外空间。
方案二:哈希表优化(推荐)
为了进一步提升效率,我们可以利用哈希表(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
复杂度分析
- 时间复杂度:。我们只需遍历一次包含 个元素的数组,哈希表的查询操作平均时间复杂度为 。
- 空间复杂度:。主要取决于哈希表的开销,我们需要在哈希表中存储最多 个元素。
关键点总结
- unordered_map:查找平均复杂度为 O(1)。
- 时间复杂度:从 O(n²) 降至 O(n)。
- 空间复杂度:为 O(n),用于维护哈希表。
结语
- 对于初学者,暴力解法是训练思维的第一步,但了解空间换时间的哈希思想是进阶的关键。
- 注意:最后返回的是下标,而不是数组元素本身。
Tip
扩展阅读:力扣官方精选题解
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
最后更新于 2025-09-27,距今已过 214 天
部分内容可能已过时
相关文章 智能推荐
1
合并两个有序数组
算法 力扣第88题:合并两个有序数组。从正向合并的繁琐到逆向双指针的极简之美,实现 $O(m+n)$ 的高效原地合并。
2
删除有序数组中的重复项
算法 力扣第26题:原地删除有序数组中的重复项。从基础的标记替换,到快慢指针(Two Pointers)的高效演进。
3
加一
算法 力扣第66题:加一。处理大整数数组的进位逻辑,从逐位检查到首位插入的技巧分析。
4
搜索插入位置
算法 力扣第35题:搜索插入位置。深入理解二分查找(Binary Search)的边界处理,实现 $O(\log n)$ 的极速搜索。
5
移除元素
算法 力扣第27题:原地移除数组中所有等于 val 的元素。深入理解快慢指针在乱序数组中的灵活应用。
随机文章 随机推荐