哈希算法
哈希算法的思维方式就是把一个字符串转化为一个以Base进制的数字。
我们通常会遇到这种问题 给你一个字符串用A表示,然后又再给你一个字符串B判断B这个字符串是否在A中或者判断B在字符串A中出现的次数,如果我们用暴力方法,很大可能会超时 因为有很多都要进行回溯操作所以不能暴力解题。
在这里我们就可以考虑用哈希算法,根据这个算法的思维,你是不是就可以把B转化为数字,然后只用判断A中有没有这个数字就可以了。
先举一个例子吧
比如 abc 这个字符串要转化为数字怎么转化呢??
比如要转化为 131 进制的
我们先写下
a b c对应的十进制是1 2 3
那么转化为131进制就是
a 对应的是 1*131的0次方
ab对应的是1*131的1次方+2
abc对应的是1*131的2次方+2*131的1次方+3*131的0次方
然后我们再思考一下 如果在abcd呢 那abcd的字符串 现在我们知道了abc的字符串我们如何根据这个abc的字符串求出abcd的字符串呢?
比如h[3]存的是abc的字符串对应的数字那么h[4]=h[3]*131+4 h[4]就是对应abcd字符串的数字了
那么怎么推导出来这个公式的呢? 我们把h[3]都乘以131是不是位次上升1位 我们再加上末尾的数字d对应的数值是4
那么问题来了 我们知道abcd字符串对应的值 如何求中间的值 也就是 bcd的值呢?
我们可以拿着abcd的数值减去a的数值*131的三次方也就是h[4]-h[1]*131的三次方就得到bcd的数值了
可是131的三次方的数值怎么保存呢 我们可以另外开一个数组p来保存131的n次方的数值
可是如果131的次方太大了就会溢出 ,所以我们要拿这个数字mod2的64次方为啥是2的64次方因为unsigned long long最大就是2的64次方 如果用这个的话 我们不用对2的64次方取余数溢出了多少就打印多少 所以用2的64次方
基本的模版如下
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;//为什么要用unsigned long long呢 因为用unsigned long long是2的64次方我们就不用mod这个数字了
const int N= 1000010,base=131;
char str[N];
ull h[N],p[N];//h数组是求【1,n】字符串的数字 p数组是求base的n次方
ull get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
scanf("%s",str+1);
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;
}
int m;
cin>>m;
while(m--)
{
int l,r;
cin>>l>>r;
cout<<get(l,r)<<endl;
}
return 0;
}
兔子与兔子
很久很久以前,森林里住着一群兔子。
有一天,兔子们想要研究自己的 DNA 序列。
我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母)。
然后我们每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子是否一模一样。
注意两个兔子一模一样只可能是他们的 DNA 序列一模一样。
输入格式
第一行输入一个 DNA 字符串 S。
第二行一个数字 m,表示 m 次询问。
接下来 m 行,每行四个数字 l 1 ,r 1 ,l 2 ,r 2 l1,r1,l2,r2 ,分别表示此次询问的两个区间,注意字符串的位置从1开始编号。
输出格式
对于每次询问,输出一行表示结果。
如果两只兔子完全相同输出 Yes,否则输出 No(注意大小写)。
数据范围
1≤length(S),m≤1000000 1≤length(S),m≤1000000
输入样例:
aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:
Yes
No
Yes
AC代码如下
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;//为什么要用unsigned long long呢 因为用unsigned long long是2的64次方我们就不用mod这个数字了
const int N= 1000010,base=131;
char str[N];
ull h[N],p[N];//h数组是求【1,n】字符串的数字 p数组是求base的n次方
ull get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
int main()
{
scanf("%s",str+1);
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;
}
int m;
cin>>m;
while(m--)
{
int l,r,l1,r1;
cin>>l>>r>>l1>>r1;
if(get(l,r)==get(l1,r1))
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
return 0;
}