“两数之和”(Two Sum)是一道非常经典的算法题目,几乎是算法入门和面试准备的必做题之一。它的经典性体现在以下几个方面:
1. 算法入门的基础题目
这道题目是许多初学者接触 哈希表(Hash Table) 或 字典(Dictionary) 的第一个应用场景。
它帮助初学者理解如何通过空间换时间,将时间复杂度从暴力解法的
O
(
n
2
)
O(n^2)
O(n2) 优化到
O
(
n
)
O(n)
O(n)。
2. 面试中的高频题目
在技术面试中,这道题目经常被用作考察候选人对哈希表的理解和应用能力。面试官可能会通过这道题目进一步延伸,考察候选人对边界条件、代码实现细节以及优化思路的掌握。
3. 多种解法,适合不同阶段的练习
这道题目有多种解法,适合不同阶段的练习:
- 暴力解法:双重循环,时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( 1 ) O(1) O(1)。
- 哈希表优化:时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)。
- 排序 + 双指针:时间复杂度 O ( n l o g n ) O(n log n) O(nlogn),空间复杂度 O ( 1 ) O(1) O(1)(但需要额外空间存储索引)。
通过这些解法,可以逐步提升对算法和数据结构的理解。
4. 问题变种的基石
“两数之和”是许多更复杂问题的基础,例如:
- 三数之和(3Sum):在数组中找出三个数,使它们的和等于目标值。
- 四数之和(4Sum):在数组中找出四个数,使它们的和等于目标值。
- 两数之和 II - 输入有序数组:数组已排序,要求使用双指针解决。
- 两数之和 IV - 输入二叉搜索树:在二叉搜索树中寻找两数之和。
这些问题都可以从“两数之和”的思路中延伸出来。
5. 实际应用场景
“两数之和”的思想在实际开发中也有广泛应用,例如:
- 查找匹配项:在数据库中查找满足某种条件的两个记录。
- 缓存优化:通过哈希表快速查找缓存中的数据。
- 金融领域:在股票市场中寻找两笔交易,使它们的收益等于目标值。
1. Two Sum
Given an array of integers nums
and an integer target
, return indices of the two numbers such that they add up to target
.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
C++ 代码实现
#include <vector>
#include <unordered_map>
using namespace std;
vector<int> twoSum(vector<int>& nums, int target) {
// 创建一个哈希表,用于存储数字及其对应的索引
unordered_map<int, int> num_to_index;
// 遍历数组
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i]; // 计算当前数字的补数
// 检查补数是否在哈希表中
if (num_to_index.find(complement) != num_to_index.end()) {
// 如果找到补数,返回补数的索引和当前索引
return {num_to_index[complement], i};
}
// 如果没有找到补数,将当前数字及其索引存入哈希表
num_to_index[nums[i]] = i;
}
// 如果没有找到解(题目保证有解,这里只是占位)
return {};
}
代码说明
- 哈希表的使用:
- 使用
unordered_map<int, int>
来存储数字及其对应的索引。 - 键(
key
)是数组中的数字,值(value
)是该数字的索引。
- 使用
- 遍历数组:
- 使用
for
循环遍历数组nums
。 - 对于每个数字
nums[i]
,计算其补数complement = target - nums[i]
。
- 使用
- 查找补数:
- 在哈希表中查找补数
complement
。 - 如果找到补数,说明当前数字和补数相加等于目标值,返回它们的索引。
- 如果没找到补数,将当前数字及其索引存入哈希表。
- 在哈希表中查找补数
- 返回结果:
- 题目保证有解,因此可以直接返回结果。
- 如果没有找到解(理论上不会发生),返回空向量。
复杂度分析
- 时间复杂度:
- O ( n ) O(n) O(n):只需要遍历一次数组,哈希表的查找和插入操作都是 O ( 1 ) O(1) O(1)。
- 空间复杂度:
- O ( n ) O(n) O(n):哈希表最多存储 n n n 个元素。
总结
这段代码通过哈希表实现了高效的两数之和查找,时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n),适合处理大规模数据。