一.问题描述
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案
示例 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]
二.问题思路
2.1类似暴力解法
这个代码的思路应该是在遍历每个元素时,对于当前元素nums[i],寻找在它之后是否存在另一个元素等于target - nums[i]。如果存在,就返回它们的下标.这个方法的优点是相比双重循环的暴力法,每次只搜索后面的元素,减少了检查的次数。例如,对于i=0,检查后面的n-1个元素;i=1,检查n-2个,总的比较次数是(n-1)+(n-2)+...+1 = n(n-1)/2,时间复杂度还是O(n²)。所以这其实还是暴力法的优化版本,但时间复杂度并没有降低到O(n)。
代码实现
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
for (int i = 0;i < nums.size();i++)
{
int findx = target - nums[i];
vector<int>::iterator it = find(nums.begin()+i+1, nums.end(), findx);
if (it != nums.end())
{
int index = distance(nums.begin(), it);
return{ i,index };
}
}
return{};
}
};
int main()
{
Solution solution;
vector<int> v = { 2, 7, 11, 15 };
vector<int> result = solution.twoSum(v, 17);
cout << result[0] << ", " << result[1] << endl; // 输出: 0, 1
return 0;
}
时间复杂度
-
平均情况:O(n²),每次遍历需调用
std::find
(时间复杂度 O(n)),总时间为 O(n²)。 -
优点:实现简单,适用于小规模数据。
-
缺点:大规模数据效率低,明显劣于哈希表法的 O(n)。
2.2 哈希表优化解
C++中的哈希表可以用`std::unordered_map`来实现。这个容器提供了快速的查找和插入操作,平均时间复杂度是O(1)。所以基本思路应该是类似的:遍历数组,对于每个元素,计算其补数(即`target - 当前元素`),然后检查这个补数是否已经在哈希表中存在。如果存在,就返回对应的下标;如果不存在,就将当前元素及其下标存入哈希表
代码实现
#include <vector>
#include <unordered_map>
using namespace std;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash; // 哈希表:值 -> 下标
for (int i = 0; i < nums.size(); ++i) {
int complement = target - nums[i];
if (hash.find(complement) != hash.end()) {
return {hash[complement], i}; // 找到补数,返回下标
}
hash[nums[i]] = i; // 将当前元素存入哈希表
}
return {}; // 题目保证有解,此行不会执行
}
};
-
时间复杂度:O(n),只需一次遍历数组。
-
空间复杂度:O(n),哈希表最多存储 n 个元素。
-
避免重复使用元素:哈希表在插入当前元素前先检查补数,确保不会使用同一个元素两次。
-
处理重复元素:哈希表保存的是元素第一次出现的下标,后续重复元素会正确匹配补数。
三.方法比较
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
暴力搜索 | O(n²) | O(1) | 小规模数据,实现简单 |
哈希表优化解法 | O(n) | O(n) | 大规模数据,实现高效 |