哈希算法
字符串的哈希算法,通俗的理解,就是将一个字符串,转化成整数
原来我们进行字符串匹配的时候,就是一个个去匹配,那么时间复杂度是o(n),如果转化成数字,去匹配那么时间复杂度会变成o(1)。
哈希算法的引入
首先联想一下二进制数,对于任意一个二进制数,我们将它化为10进制的数的方法如下(以二进制数1101101为例):
1101101=1 * 2 ^ 6+1 * 2 ^ 5+0 * 2 ^ 4+1 * 2 ^ 3+1 * 2 ^ 2+1*2 ^1+1
这是二进制转化为十进制
那么如果我们想把字符串转化成十进制的整数,那么我们是不是就可以把这个字符串设为p进制的数,然后将a~z的字母设为1 ~26,那么我们在进行转化的时候是不是就可以按照二进制转换成十进制那样那么哈希就是经过一个转换,再模上一个q,就是哈希的解法了。
上图是我们以字符串abc为示范
得到的结果就是我们想要的整数,但是在有时候,难免会出现,两个字符串不相同但是整数相同的情况,为了尽量减少这种情况,我们把p往往取为131或者13331,然后q我们一般取2的64次方,因为我们把哈希算出来的整数存放在unsigned long long 中,而这个类型的数据溢出就相当于系统自动帮你进行2的64次方取模运算,所以我们在算哈希值的时候,就可以不用取模了。
哈希值
我们在算一个字符串的哈希值的时候,会把前缀的哈希值都算出来
我们再以字符串abc为例,通过观察,我们可以看出,ab的哈希值等于a的哈希值乘上一个p再加b的值,就相当于把原本在个位的a移到十位上,把b加到个位里,所以我们可以得到一个式子:
h[i]=h[i-1]*p+s[i]-‘a’+1;
后面的这个s[i]-‘a’+1,就相当于a=1,b=2以此类推。
部分代码:
for(int i=1;i<=strlen(a);i++)
{
h[i]=h[i-1]*p+s[i]-'a'+1;
}//a是字符串数组,h是存放哈希值的
求子串的哈希值
如果知道我们1到r的哈希值,让我们求h到r的哈希值
这个求的过程有点类似于给你一个数比如210,让你求个位加十位的值
那么我们也可以得到一个式子w[h-r]=h[h]-h[r]*q ^ (h-r+1);
为了减少时间复杂度我们一般用一个数组q直接保存q的次方值
代码如下
q[0]=1;
for(i=1;i<=strlen(a);i++)
{
q[i]=q[i-1]*base;
}
一般的总代码
#include<stdio.h>
#include<string.h>
char a[1000010];
unsigned long long h[1000010],q[1000010];//一定要注意数据类型
int main()
{
int base=131;//将p取为131
scanf("%s",a+1);
int n,m,i;
m=strlen(a+1);
h[0]=0;
q[0]=1;
for(i=1;i<=m;i++)//从1开始
{
h[i]=h[i-1]*base+(a[i]-'a'+1);
q[i]=q[i-1]*base;
}
以上代码就是求哈希值的代码。
来源:CSDN
作者:a921893396
链接:https://blog.csdn.net/a921893396/article/details/104143073