知识点
哈希冲突
哈希冲突是利用哈希函数时,对哈希值取模(哈希值往往很大,免不了取模),出现了哈希值重复的情况,这样会导致程序出现差错。
经过科学的计算,执行一次哈希函数的错误率为20%!这样的错误率是不容小觑的。
双哈希
我们可以通过双哈希来解决这个问题
所谓双哈希,就是进行两遍哈希,换一下底数和模数,这样可以讲哈希函数的错误率降低到0.001%
这样哈希冲突就很难发生了
(温馨提示:底数最好使用与涉及字符数量相近的数,如:全是任意字符,底数可以选128,131等,模数最好是大质数,如:1e9+7,998244353等)
例题
题目:不同子串
时间限制:2秒 内存限制:256M
题目描述
给你一个仅由小写字母组成的长度为 n 的字符串,问你其中有多少个不同的长度为 L 的子串。
输入样例
10 2
abababbabc
输出样例
4
数据范围
对于 100% 的数据, 1 ≤ L ≤ N ≤ 10 6 1≤L≤N≤10^6 1≤L≤N≤106
不同子串题解
思路
字符串比较太慢了,可以转成哈希值进行计算,哈希值会很大,所以只能用双哈希加取模。
首先求出前缀哈希值,然后依次求出区间哈希值
再将两次的哈希值存入pair数组中进行排序,排完序后挨个遍历一遍,判断是否重复,不重复ans+1
最后输出答案
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1000005;
ll n,l,k,cnt;
string s;
pair<ll,ll> p[N];
ll ans;
struct hash{
ll sed,mod,h[N],pw[N];
void init(int sed_in,int mod_in){
sed=sed_in,mod=mod_in;
pw[0]=1;
for(int i=1;i<N;i++){
pw[i]=pw[i-1]*sed%mod;
}
}
void make(string s){
h[0]=s[0]%mod;
for(int i=1;i<s.size();i++){
h[i]=(h[i-1]*sed%mod+s[i])%mod;
}
}
ll get(ll l,ll r){
return (h[r]-h[l-1]*pw[r-l+1]%mod+mod)%mod;
}
}s1,s2;
int main(){
cin>>n>>l>>s;
s1.init(128,1e9+7);
s2.init(131,998244353);
s=" "+s;
s1.make(s);
s2.make(s);
for(int i=1;i<=1+n-l;i++){
cnt++;
p[cnt].first=s1.get(i,i+l-1);
p[cnt].second=s2.get(i,i+l-1);
}
sort(p+1,p+1+cnt);
for(int i=1;i<=cnt;i++){
if(i==1||p[i]!=p[i-1]){
ans++;
}
}
cout<<ans;
return 0;
}