文章目录
一、什么是哈希表
哈希表是散列表,就是通过关键码值而直接进行访问的一种数据结构
哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素
其内部由一个个key:value 样式的键值对组成。
哈希表中的key通过哈希函数得到内存地址,然后将key和value放到对应的内存地址,从而实现通过key获取Value的方式
哈希碰撞:2个不同的key通过哈希函数(hash function)得到了相同的内存地址,也就是是内存地址已经被一个占用了,解决方法是将其中之一变为链表结构,使用next指向。这样内存地址就不会重复,但是会影响查询
二、哈希表常见结构介绍
总体结构上分为数组、set、map
- 数组也是一种意义上的哈希表
- set的结构中每个元素都是一个值(类似于数组)
- map的结构是一个 key:value 的数据结构
重点讲:unordered_map(哈希表)
- unordered_map底层存储的是<key,value>键值对,可以通过key快速的索引到value unordered_map内部因为是数据是通过映射存入哈希桶内的,所以对unordered_map进行遍历得到的是一个无序的序列
- unordered_map通过key进行访问的速度比map快,但是遍历元素的迭代效率就要低于map了。unordered_map也实现了operator[ ] 可以通过key直接访问到value
leetcode经典例题
242 有效的字母异位词
题目来源:https://leetcode.cn/problems/valid-anagram/description/
思路
使用哈希表下标索引,判断这两个字符串每个字符出现的次数即可。
编程
cpp
class Solution {
public:
bool isAnagram(string s, string t) {
int hash[27]={0};
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) return false;
}
return true;
}
};
349 两个数组的交集
题目来源:https://leetcode.cn/problems/intersection-of-two-arrays/description/
思路
选择unordered_set避免数据重复,将nums1的序列存入哈希表unordered_set中,遍历查找nums2相同的值即可
编程
cpp
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> ans;
unordered_set<int> a(nums1.begin(),nums1.end());
for(int i=0;i<nums2.size();++i){
if(a.find(nums2[i])!=a.end()){
ans.insert(nums2[i]);
}
}
return vector<int>(ans.begin(),ans.end());
}
};
1 两数之和
思路
选择unordered_map来存储数值和下标,遍历nums数列,若在unordered_map找到target-nums[i]对应的值,则输出它们的下标,找不到则将当前的值和下标存入哈希表即可
编程
cpp
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> ans;
for(int i =0;i<nums.size();i++){
auto t= ans.find(target-nums[i]);
if(t==ans.end()){
ans.insert(make_pair(nums[i],i));
}
else{
return {t->second,i};
}
}
return {};
}
};
454 四数相加II
思路
先对式子做移项处理,nums1[i] + nums2[j] =-(nums3[k] + nums4[l] ),那么我们也是选择用unordered_map来存储数组,先将nums1[i] + nums2[j] 的所有数存入哈希表中,然后在哈希表里面找-(nums3[k] + nums4[l] ),若匹配则计数器加上哈希表-(nums3[k] + nums4[l] )的个数,最后返回计数器即可
编程
cpp
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> m;
int ans=0;
for(auto i : nums1)
for(auto j : nums2){
m[i+j]++;
}
for(auto i : nums3)
for(auto j : nums4){
int t=-(i+j);
if(m.find(t)!=m.end()) ans+=m[t];
}
return ans;
}
};
字符串哈希
题目来源:https://www.luogu.com.cn/problem/P3370
前言
字符串哈希是一种将字符串映射为整数的算法。哈希函数将字符串映射到一个固定大小的整数,这个整数通常称为哈希值或哈希码。
思路
首先防止数据溢出,我们需要用到unsigned long long(当数据超出2^64^时会自动取模),参数p取131防止哈希碰撞,对于这题来说用的是进制哈希(把每个字符看作每个进制位上的一个数字,这个串转换为一个基于进制p的数),将字符串通过进制哈希转换完后进行排序,最后比较相邻元素即可
编程
cpp
const int N=1e4+5;
ULL a[N],p=131,h=0;
void solve(){
int n;cin >> n;
for(int i=0;i<n;++i){
string s;cin >> s;
h=0;
for(int i=0;i<s.size();++i){
h=h*p+s[i];
}
a[i]=h;
}
int ans=0;
sort(a,a+n);
for(int i=0;i<n;++i){
if(a[i]!=a[i+1]) ans++;
}
cout << ans;
return ;
}