什么是hash
Hash是把任意长度的输入(又叫做预映射pre-image) 算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
进制哈希
我们计算机中常用的为进制哈希
步骤:
- 首先定义一个进制数base,并设一个模数mod,mod最好大一些。base和mod最好互质。
- 枚举字符串的每一位,与base^i相乘加到ans里,注意对mod取模。比如字符串“ABCDE", base=26, mod=1e9+7
- ans=(A*base^4+B*base^3+C*base^2·+D*base^1+E*base^0)%mod
哈希碰撞(冲突)
两个不同字符串拥有相同的hash值,在查询的时候,会认为这两个字符串相同,而其实他们不相同。
减少哈希冲突的概率:选取合适的base(通常选131,13331)、mod、双哈希
练习
- [P3370 【模板】字符串哈希](https://www.luogu.com.cn/problem/P3370)
题解:对每个字符串进制哈希,并将哈希值存到ans数组里,统计里面不一样的值的个数,输出即可。
代码实现如下:
#include<bits/stdc++.h>
using namespace std;
char s[1501];
long long ans[10001],hashe[10001][1501];
int main()
{
int n,base=131,number=1,len=0;
long long mod=1e9+7;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%s",s);
len=strlen(s);
//进制哈希
for(int j=0; j<len; j++)
{
if(j==0)hashe[i][j]=s[j];
else hashe[i][j]=(hashe[i][j-1]*base+s[j])%mod;
}
ans[i]=hashe[i][len-1];
}
sort(ans+1,ans+n+1);
//统计数组ans中不相同的数字个数
for(int i=1;i<n;i++)
{
if(ans[i]!=ans[i+1])
number++;
}
printf("%d",number);
return 0;
}