所谓字符串哈希就是构造一个数字使之唯一代表一个字符串。
构造方法:
假如给你一个数字1166,形式上你只知道它只是1和6的组合,但你知道它代表的实际大小1*10^3+1*10^2+6*10^1+6*10^0。
同理,给你一个字符串,要把它转换为数字,就可以先把每一个字符都先对应一个数字,然后把它们按照顺序乘以进制的幂进行相加。
如abcd,我们取各个字母的ASCII码值减去a的ASCII码值+1,便得到abcd分别对应数字1,2,3,4,接下来再取一个进制如23进行组合即可。保险起见,进制要大于每一个字符对应的数字(负数情况另外讨论)。否则会出现如下情况:
a b c d e 分别对应 1 2 3 4 25,若此时取23进制,那么ab和e的哈希值相同,会被判断为是同一字符串。
一、例题:P3370 【模板】字符串哈希:https://www.luogu.org/problemnew/show/P3370
#include
using namespace std;
typedef unsigned long long ULL; //哈希值可能非常大
const int N=1e4+5;
const ULL B=29; //进制
ULL hashT[N]; //用于储存每一个字符串的哈希值
char input[N];
int n,tmp;
int ans;
ULL hashf(char s[]) //生成字符串哈希值
{
tmp=0;
for(int i=0;i>n;
for(int i=0;i
二、P2957 [USACO09OCT]谷仓里的回声Barn Echoes:https://www.luogu.org/problemnew/show/P2957
与上一题不同的是,我们要的不只是一个字符串的哈希值,而是一个字符串的“滚动哈希值”,就是从第1位开始到任意位的子串的哈希值,便于之后取子串的哈希值。
#include
using namespace std;
typedef unsigned long long ULL;
const int N=1e3+5;
const ULL B=29;
char s1[N],s2[N];
ULL hashT1[N],hashT2[N]; //分别储存两个字符串的滚动哈希值
ULL power[N]; //存放取字串时需要乘的幂次
int main()
{
int ans=0,cnt1=0,cnt2=0;
power[0]=1;
for(int i=1;i<=N;i++) power[i]=power[i-1]*B;
scanf("%s\n%s",s1+1,s2+1);
int len1=strlen(s1+1);
int len2=strlen(s2+1);
for(int i=1;i<=len1;i++) //从左往右存的好处就在于取字串时只需乘进制,而不是除进制
hashT1[i]=hashT1[i-1]*B+(ULL)(s1[i]-'a'+1);
for(int i=1;i<=len2;i++)
hashT2[i]=hashT2[i-1]*B+(ULL)(s2[i]-'a'+1);
ULL hash1,hash2;
for(int i=1,j=len2; i<=len1&&j>=1; i++,j--) //从第一个字符串头及第二个字符串尾开始
{
hash1=hashT1[i];
hash2=hashT2[len2]-hashT2[j-1]*power[i];
if(hash1==hash2) cnt1=i; //因为是哈希值进行比较,如果哈希值一样,则说明i前和j后是同一个字符串,i即长度
}
for(int i=len1,j=1; i>=1&&j<=len2; i--,j++) //从第一个字符串尾及第二个字符串头开始
{
hash1=hashT1[len1]-hashT1[i-1]*power[j];
hash2=hashT2[j];
if(hash1==hash2) cnt2=j;
}
ans=max(cnt1,cnt2);
cout<
三、P1381 单词背诵:https://www.luogu.org/problemnew/show/P1381
和之前尺取那篇博客中提到的http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1813相似。
思路就是求取每一个字符串的哈希值,然后利用哈希值+map进行尺取。
#include
using namespace std;
typedef unsigned long long ULL;
const int N=1e3+5;
const int M=1e5+5;
const int L=15;
const int B=29;
char s1[L],s2[L];
ULL hashT1[N];
ULL hashT2[M];
int n,m;
maphaved; //文章中是否出现过某单词
mapwordHave; //要背的单词
mapsumHave; //用于判断计算文章中有的需要背的单词的数量
int hashf(char s[])
{
int tmp=0;
for(int i=0;i>n;
for(int i=0;i>m;
int sumWord=0;
for(int i=0;i1 || wordHave[hashT2[l]]==0)
{
haved[hashT2[l]]--;
l++;
}
ans=min(ans,r-l+1);
}
cout<