两数之和,题目来自leetcode
cpp
//两数之和,首先将其列出一一对应,然后对其进行遍历相加,相加值等于,则返回,否则不返回
#include<vector>
#include<unordered_map>
using namespace std;
//法1.暴力求解
class Sloution {
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[i] + nums[j] == target)
{
return{ i,j };
}
}
}
return{};
}
};
//法2,哈希表求解
class Sloution_1 {
public:
vector<int> TwoSum(vector<int>&nums_, int targets){
//初始化哈希表
unordered_map<int, int> hashmap;
//进行一次遍历
for (int i = 0; i < nums_.size(); i++)
{
//计算需要的数值
int complement = targets - nums_[i];
//检查hashmap中是否存在需要的值,首次遍历其中为空,必定不存在,其中自动存在迭代器,不需要自己再写,查找时
if (hashmap.find(complement) != hashmap.end())
{
return{ hashmap[complement],i };//找到了,进行返回
}
hashmap[nums_[i]] = i;//将查找过的数值存储到其中,为下次做准备
}
return{};
}
};
下面介绍unordermap的基础操作
1. 基本操作
创建和初始化
#include <unordered_map>
#include <string>
using namespace std;
// 创建空哈希表
unordered_map<int, string> map1;
// 初始化列表
unordered_map<int, string> map2 = {
{1, "Alice"},
{2, "Bob"},
{3, "Charlie"}
};
// 复制构造
unordered_map<int, string> map3(map2);
插入操作
unordered_map<int, string> map;
// 1. 使用[]操作符(如果键存在则覆盖)
map[1] = "Apple";
map[2] = "Banana";
// 2. insert() 方法
map.insert({3, "Cherry"});
map.insert(make_pair(4, "Date"));
// 3. emplace() 高效插入
map.emplace(5, "Elderberry");
// 检查插入是否成功
auto result = map.insert({1, "Apricot"}); // 键1已存在,插入失败
if (!result.second) {
cout << "插入失败,键已存在" << endl;
}
2. 查找操作
unordered_map<int, string> map = {{1, "Apple"}, {2, "Banana"}};
// 1. find() 方法(推荐)
auto it = map.find(2);
if (it != map.end()) {
cout << "找到: " << it->first << " -> " << it->second << endl;
} else {
cout << "未找到" << endl;
}
// 2. count() 方法
if (map.count(1) > 0) {
cout << "键存在" << endl;
}
// 3. at() 方法(安全访问)
try {
string value = map.at(1); // 如果键不存在会抛出异常
} catch (const out_of_range& e) {
cout << "键不存在" << endl;
}
// 4. []操作符(不安全,会创建新键)
string value = map[3]; // 如果键3不存在,会创建一个空值
3. 删除操作
unordered_map<int, string> map = {
{1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}
};
// 1. erase() 通过键
map.erase(2); // 删除键为2的元素
// 2. erase() 通过迭代器
auto it = map.find(3);
if (it != map.end()) {
map.erase(it);
}
// 3. erase() 删除范围
auto begin = map.find(1);
auto end = map.find(4);
map.erase(begin, end); // 删除[1,4)范围的元素
// 4. clear() 清空所有元素
map.clear();
4. 遍历操作
unordered_map<int, string> map = {{1, "A"}, {2, "B"}, {3, "C"}};
// 1. 使用迭代器
cout << "迭代器遍历:" << endl;
for (auto it = map.begin(); it != map.end(); ++it) {
cout << it->first << " -> " << it->second << endl;
}
// 2. 范围for循环(推荐)
cout << "范围for循环:" << endl;
for (const auto& pair : map) {
cout << pair.first << " -> " << pair.second << endl;
}
// 3. 结构化绑定(C++17)
cout << "结构化绑定:" << endl;
for (const auto& [key, value] : map) {
cout << key << " -> " << value << endl;
}
5. 容量查询
unordered_map<int, string> map = {{1, "A"}, {2, "B"}};
cout << "大小: " << map.size() << endl;
cout << "是否为空: " << map.empty() << endl;
cout << "桶数量: " << map.bucket_count() << endl;
cout << "负载因子: " << map.load_factor() << endl;
cout << "最大负载因子: " << map.max_load_factor() << endl;
6. 桶操作
unordered_map<int, string> map = {{1, "A"}, {2, "B"}, {3, "C"}};
// 查看特定键所在的桶
int key = 2;
size_t bucket = map.bucket(key);
cout << "键" << key << "在桶" << bucket << endl;
// 查看桶的大小
cout << "桶" << bucket << "的大小: " << map.bucket_size(bucket) << endl;
// 遍历特定桶中的元素
for (auto it = map.begin(bucket); it != map.end(bucket); ++it) {
cout << "桶中的元素: " << it->first << " -> " << it->second << endl;
}
7. 哈希策略控制
unordered_map<int, string> map;
// 设置最大负载因子
map.max_load_factor(0.7f);
// 预分配桶数量(减少重新哈希)
map.reserve(100);
// 重新哈希
map.rehash(50);
8. 两数之和的完整示例
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashmap;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
// 使用find查找补数
auto it = hashmap.find(complement);
if (it != hashmap.end()) {
return {it->second, i};
}
// 插入当前元素
hashmap[nums[i]] = i;
// 调试信息:打印当前哈希表状态
cout << "插入后哈希表大小: " << hashmap.size() << endl;
cout << "当前负载因子: " << hashmap.load_factor() << endl;
}
return {};
}
};
// 测试函数
int main() {
Solution sol;
vector<int> nums = {2, 7, 11, 15};
int target = 9;
vector<int> result = sol.twoSum(nums, target);
if (!result.empty()) {
cout << "结果: [" << result[0] << ", " << result[1] << "]" << endl;
} else {
cout << "未找到解" << endl;
}
return 0;
}
9. 性能特点
操作 | 平均复杂度 | 最坏复杂度 | 说明 |
---|---|---|---|
插入 | O(1) | O(n) | 插入单个元素 |
查找 | O(1) | O(n) | 根据键查找 |
删除 | O(1) | O(n) | 根据键删除 |
遍历 | O(n) | O(n) | 遍历所有元素 |
10. 常用技巧
统计频率
vector<int> nums = {1, 2, 2, 3, 3, 3};
unordered_map<int, int> freq;
for (int num : nums) {
freq[num]++; // 自动初始化为0然后递增
}
// 输出: 1:1, 2:2, 3:3
检查重复
vector<int> nums = {1, 2, 3, 2, 4};
unordered_map<int, bool> seen;
for (int num : nums) {
if (seen[num]) {
cout << "重复元素: " << num << endl;
}
seen[num] = true;
}
这些是 unordered_map
最常用的操作,掌握它们可以高效地解决很多算法问题。