HELLO WOR|

kingwzun

园龄:3年6个月粉丝:111关注:0

2022-07-28 20:31阅读: 1765评论: 0推荐: 0

字符串哈希(Hash)

基础概念

作用: 快速判断两个串是否相等,判断一个字符串是否出现过。
更多应用可以看这篇好文

字符串哈希实质上就是把每个不同的字符串转成不同的整数。
可以发现,与一个string有关的HASH值不仅仅跟每个字符的个数有关,还和字符所在的位数有关。

比如说对于字符串:abc,base设为32
a=hash[1]=aa+1=1
ab=hash[2]=hash[1]32+ba+1=32+2=34
abc=hash[3]=hash[2]32+ca+1=1088+3=1091
也就是说:abc,可以映射为整数1091
也就是把字符串看成32进制的一个数。

通过简单的思考,即可知道转化公式为:
hash[i]=hash[i−1]∗base+idx(s[i]);

注意:

  1. 为了尽量避免冲突,base建议取:131/1331

  2. 为了方便将变量定义为unsigned long long。
    当存储的数据大于unsigned long long的存储范围时,会自动mod 264−1,就不用mod其他质数来保证唯一性了。

138. 兔子与兔子

模板题
题意:
每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子 DNA 序列是否一模一样。
代码:

#include <bits/stdc++.h>
#define ins 0x3f3f3f3f
#define pii pair<int, int>
#define ull unsigned long long
using namespace std;
const int N = 1000001,base=131;
ull h[N],p[N];
char str[N];
ull get(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
void build(){
int n=strlen(str+1);
p[0]=1;
for(int i=1;i<=n;i++){
h[i]=h[i-1]*base+str[i]-'a'+1;
p[i]=p[i-1]*base;
}
}
void solve()
{
cin>>str+1;
build();
int n;
cin >> n;
int l1,r1,l2,r2;
for(int i=0;i<n;i++){
cin>>l1>>r1>>l2>>r2;
if(get(l1,r1)==get(l2,r2)) puts("Yes");
else puts("No");
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}

双哈希

思想:
按照不同的模数分别进项哈希,然后分别比较。
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const ull mod1 = 1e9 + 7, mod2 = 2147483647;
const int N = 4e5 + 10;
const int p = 131;
ull a1[N], a2[N], h1[N], h2[N];
pair<ull, ull> res[N];
map<pair<ull, ull>, ull> mp;
void hash1(string s)
{ //预处理hash函数前缀和
a1[0] = 1;
int n = s.size();
for (int i = 1; i <= n; i++)
{
a1[i] = a1[i - 1] * p % mod1;
h1[i] = (h1[i - 1] * p % mod1 + (s[i - 1] - 'a' + 1)) % mod1;
}
}
void hash2(string s)
{ //预处理hash函数前缀和
a2[0] = 1;
int n = s.size();
for (int i = 1; i <= n; i++)
{
a2[i] = a2[i - 1] * p % mod2;
h2[i] = (h2[i - 1] * p % mod2 + (s[i - 1] - 'a' + 1)) % mod2;
}
}
ull get1(int l, int r)
{ //计算s[l--r]的hash值
return (h1[r] - h1[l - 1] * a1[r - l + 1] % mod1 + mod1) % mod1;
}
ull get2(int l, int r)
{ //计算s[l--r]的hash值
return (h2[r] - h2[l - 1] * a2[r - l + 1] % mod2 + mod2) % mod2;
}
int main()
{
int n;
cin >> n;
string s;
int pos = 0;
while (n--)
{
cin >> s;
int len = s.size();
hash1(s);
hash2(s);
mp[{h1[len], h2[len]}]++;
for (int i = 1; i + i < len; i++)
{ //寻找字符串s中前部分和后部分相同的子串
if (get1(1, i) == get1(len - i + 1, len) && get2(1, i) == get2(len - i + 1, len))
{
res[pos++] = {get1(i + 1, len - i), get2(i + 1, len - i)};
}
}
}
ll ans = 0;
for (int i = 0; i < pos; i++)
{ //统计与子串相同的字符串
ans += mp[res[i]];
}
for (auto it : mp)
{ //统计相同字符串
ans += it.second * (it.second - 1) / 2;
}
cout << ans << endl;
return 0;
}

本文作者:kingwzun

本文链接:https://www.cnblogs.com/kingwz/p/16530119.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   kingwzun  阅读(1765)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起