一、哈希表
哈希表是将大范围数据映射到小范围的存储方式。映射需要设定一个哈希函数。有常规数字哈希以及字符串哈希。
1.数字哈希
数字哈希的哈希函数是(x%N+N)%N,并且要去N是质数,以减少冲突的情况。对于整数就就是直接模N,但是考虑让负数模N和整数的值一样,需要改成这个样子。
映射后,可能有多个数字被映射成相同的k值,那么需要处理冲突。常见方法有开放寻址法和拉链法。
(1)拉链法
拉链法顾名思义,在每个k值上拉出一条链表,由链表存储映射到这个k值上的x值。
#include<iostream>
#include<cstring>
using namespace std;
const int N =100003;
int h[N],e[N],ne[N],idx;
void insert(int x)
{
int k=(x % N + N) % N;//哈希函数
e[idx]=x;
ne[idx]=h[k];
h[k]=idx++;
}
bool find(int x)
{
int k=(x %N + N) % N;
for(int i=h[k];i!=-1;i=ne[i])
if(e[i]==x) return true;
return false;
}
int main()
{
int n; cin>>n;
memset(h,-1,sizeof h);//全部设为1 在cstring里面
while(n--)
{
string op;
cin>>op;
int x;
cin>>x;
if(op=="I") insert(x);
else
{
if(find(x)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3449879/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(2)开放寻址法
找到x需要存储的k值,如果k已被占用,就存储到k+1,如果仍被占用,就继续往下走,直到x被存储。为此需要一个null标记是否为空。开的数组需要时数据的2~3倍。
#include<iostream>
#include<cstring>
using namespace std;
const int N =200003;
int h[N],null=0x3f3f3f3f;
int find(int x)//返回x应该插入的位置
{
int t=(x %N + N) % N;
while(h[t]!=null&&h[t]!=x)//有元素且不是x
{
t++; if(t==N) t=0;
}
return t;
}
int main()
{
int n; cin>>n;
memset(h,0x3f,sizeof h);//全部设为1 在cstring里面
while(n--)
{
string op;
cin>>op;
int x;
cin>>x;
int k=find(x);
if(op=="I") h[k]=x;
else
{
if(h[k]==null)cout<<"No"<<endl;//x应该插入的位置没有值
else cout<<"Yes"<<endl;
}
}
return 0;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3449879/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.字符串哈希
字符串前缀哈希,将1~n的字符串映射为一个p进制数(最后对Q取模)。h存储的是前n个字符的哈希值。
注意不能映射为0(方便起见数组从1开始存储),这样就会引起冲突。根据经验公式,P=131或者133331,Q=2^64时,基本不会冲突。
没一个字符串的哈希值是固定的,当我们需要计算某个子串的哈希值时,方法如图。
因此判断两个字符串是否相等,比较哈希值即可。
哈希值数组构造方式易知为
//这里填你的代码^^
#include<iostream>
using namespace std;
const int N =100010,P=131;
typedef unsigned long long ULL;
int h[N],p[N];//p数组预处理p的n次方(p[n]=p^n)
char str[N];
int n,m;
ULL gethash(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];//计算公式
}
int main()
{
cin>>n>>m>>str+1;
p[0]=1;
for(int i=1;i<=n;i++)
{
p[i]=p[i-1]*P;
h[i]=h[i-1]*P+str[i];//构造方式
}
while(m--)
{
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(gethash(l1,r1)==gethash(l2,r2)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/3451665/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。