哈希表理论基础
常见的三种哈希结构
当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。
数组
set (集合)
map(映射)
在C++中,set 和 map 分别提供以下三种数据结构,其底层实现以及优劣如下表所示:
集合 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
std::set | 红黑树 | 有序 | 否 | 否 | O(log n) | O(log n) |
std::multiset | 红黑树 | 有序 | 是 | 否 | O(logn) | O(logn) |
std::unordered_set | 哈希表 | 无序 | 否 | 否 | O(1) | O(1) |
std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。
映射 | 底层实现 | 是否有序 | 数值是否可以重复 | 能否更改数值 | 查询效率 | 增删效率 |
std::map | 红黑树 | key有序 | key不可重复 | key不可修改 | O(logn) | O(logn) |
std::multimap | 红黑树 | key有序 | key可重复 | key不可修改 | O(log n) | O(log n) |
std::unordered_map | 哈希表 | key无序 | key不可重复 | key不可修改 | O(1) | O(1) |
总结一下,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
但是哈希法也是牺牲了空间换取了时间,因为我们要使用额外的数组,set或者是map来存放数据,才能实现快速的查找。
哈希表-有效的字母异位词
哈希结构:数组
//Hash哈希表-有效的字母异位词
#include<bits/stdc++.h>
using namespace std;
string s, t;
int Hash[30], temp;
int main(){
cin >> s >> t;
for (int i = 0; i < s.size(); i++){
Hash[s[i] - 'a']++;
}
for (int i = 0; i < t.size(); i++){
Hash[t[i] - 'a']--;
}
for (int i = 0; i <= 26; i++){
if (Hash[i] != 0){
printf("false\n");
temp = 1;
break;
}
}
if (temp == 0){
printf("true\n");
}
return 0;
}
哈希表-两个数组的交集
哈希结构:unordered_set
//Hash哈希表-两个数组的交集
#include<bits/stdc++.h>
using namespace std;
unordered_set<int> se;
unordered_set<int> ans_set;
int n, m;
int nums1[1000], nums2[1000];
int main(){
cin >> n >> m;
for (int i = 0; i < n; i++){
cin >> nums1[i];
se.insert(nums1[i]);
}
for (int i = 0; i < m; i++){
cin >> nums2[i];
}
for (int num : nums2){
if (se.find(num) != se.end()){
ans_set.insert(num);
}
}
for (auto it = ans_set.begin(); it != ans_set.end(); it++){
printf("%d ", *it);
}
return 0;
}
哈希表-快乐数
哈希结构:unordered_set
//Hash哈希表-快乐数
#include<bits/stdc++.h>
using namespace std;
unordered_set<int> ans_set;
int n, temp;
int getSum(int n){
int sum = 0;
while (n){
sum += (n % 10) * (n % 10);
n /= 10;
}
return sum;
}
bool judgeNum(int n){
while (true){
temp = getSum(n);
if (temp == 1){
return 1;
}
else {
if (ans_set.find(temp) != ans_set.end()){
return 0;
}
else {
ans_set.insert(temp);
}
}
n = temp;
}
}
int main(){
while (cin >> n){
if (judgeNum(n)){
printf("true\n");
}
else {
printf("false\n");
}
}
return 0;
}
哈希表-两数之和
哈希结构:unordered_map
//Hash哈希表-两数之和
#include<bits/stdc++.h>
using namespace std;
int n, target;
int nums[10000];
unordered_map<int, int> ans_map;
int main(){
cin >> n;
for (int i = 0; i < n; i++){
cin >> nums[i];
}
cin >> target;
for (int i = 0; i < n; i++){
unordered_map<int, int>::iterator it;
it = ans_map.find(target - nums[i]);
if (it != ans_map.end()){
printf("%d %d\n", it->second, i);
}
else {
ans_map.insert(pair<int, int>(nums[i], i));
}
}
return 0;
}
总结
简而言之,哈希表就是一个容器,哈希法就是以空间换取时间的方式,可以大幅降低时间复杂度,从而提高程序的运行效率,哈希表结合了STL中的容器,在解题上技巧性很强,主要用于查询某个元素是否出现过。