简单哈希–操作字符串
题目链接: HDU 1686 Oulipo
题意:
给你两个字符串str1,str2.
问:str1在str2中出现了多少次?
实际上这一题是KMP的简单的模板题。这里用hash同样可以更加简单的解决
Hash的三个步骤:
1,初始化 ( init() )
2,建哈希 ( make_hash() )
3,取哈希 ( get_hash() )
/*
****** Q:代码里为什么没有取模?
****** A:小技巧:取模的数用2^64,这样直接用unsigned long long存储,溢出的结果就是取模的结果
取模1000000007单哈希这里会WA
*/
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int maxx=1000019;
ull hash_1[maxx],hash_2[maxx],p[maxx];
char ch1[maxx],ch2[maxx];
void init()
{
p[0]=1;
for(int i=1;i<=maxx;i++)
p[i]=p[i-1]*13331;//常取 131,13331
}
int make_hash(char ch[],ull hash_[])
{
int len=strlen(ch+1);
for(int i=1;i<=len;i++)
{
hash_[i]=hash_[i-1]*13331+(ch[i]);
}
return len;
}
ull get_hash(int l,int r)
{
return hash_2[r]-(hash_2[l-1]*p[r-l+1]);
// 为什么*p[r-l+1]?
// r-l+1是区间的长,由于hash是乘13331后+ch[i]累加的,
// 相当于 [1,r] 比 [L,r] 中多了 (r-l+1)个1331倍的hash[l-1],减去就是[l,r]了
// p[(r-l+1)]=13331^(r-l+1);
}
int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",ch1+1);
scanf("%s",ch2+1);
int len1=make_hash(ch1,hash_1);
int len2=make_hash(ch2,hash_2);
int ans=0;
for(int i=1;i+len1-1<=len2;i++)
{
if(get_hash(i,i+len1-1)==hash_1[len1])//判同,hash值相等
ans++;
}
printf("%d\n",ans);
}
return 0;
}