哈希字符串
哈希字符串
哈希字符串算法的意义就是把一串复杂的字符串通过哈希算法转化为一个整数,将复杂的东西转化为简单的东西来做,这样匹配两个字符串的时间复杂度就降低到了O(1),因为只需要比较两个整数,但是该算法也有很大的缺点,就是不稳定,该算法是把从第一个字符到指定字符这一段字符通过一个公式给定一个值,所以hash数组存的是每一段字符的hash值,这样就存在着两个不同的字符串有相同hash值的可能,但是通过经验确定,把式子的某些值定为某个特殊数字能降低这种可能性。
首先,我们需要给每个字符它自己的特殊的值,比如一串小写字母,可以把a->z看成1->24
比如 字符串为“abcd”
hash[1]=‘a’-‘a’+1
hash[2]=hash[1]*p+‘b’-‘a’+1
…
以此类推
这里的p可以看成是把字母的值转化为p进制
p通常定位131或者13331更加稳定,容错率更高
下面是一个利用到这个算法的例题:
很久很久以前,森林里住着一群兔子。
有一天,兔子们想要研究自己的 DNA 序列。
我们首先选取一个好长好长的 DNA 序列(小兔子是外星生物,DNA 序列可能包含 26 个小写英文字母)。
然后我们每次选择两个区间,询问如果用两个区间里的 DNA 序列分别生产出来两只兔子,这两个兔子是否一模一样。
注意两个兔子一模一样只可能是他们的 DNA 序列一模一样。
输入格式
第一行输入一个 DNA 字符串 S。
第二行一个数字 m,表示 m 次询问。
接下来 m 行,每行四个数字 l1,r1,l2,r2,分别表示此次询问的两个区间,注意字符串的位置从1开始编号。
输出格式
对于每次询问,输出一行表示结果。
如果两只兔子完全相同输出 Yes,否则输出 No(注意大小写)。
数据范围
1≤length(S),m≤1000000
输入样例:
aabbaabb
3
1 3 5 7
1 3 6 8
1 2 1 2
输出样例:
Yes
No
Yes
解题思路:先把整个字符串所有前缀的hash值算出来存入h数组,然后通过所存的hash值算出子串单独拿出来的hash值,并且进行比较,如果hash值相同就说明他们是相同的。
for(i=1;i<=l;i++)
{
h[i]=h[i-1]*131+s[i]-'a'+1;//算出所有前缀的hash值
p[i]=p[i-1]*131;//记录位次,方便对子串hash值进行计算
}
if(h[r1]-h[l1-1]*p[r1-l1+1]==h[r2]-h[l2-1]*p[r2-l2+1])//等式两边分别为子串的hash值
printf("Yes\n");
else
printf("No\n");
简单解释下子串hash值的计算:
*h[r-l]=h[r]-h[l-1]p[r-l+1],h[l-1]要乘个p[r-l+1]是为了把(1,l-1)这一段字符的hash值提高到和(1,r)这一段同一个级别(同一个p进制的位次),但是只是把前面的字符提高位次,就相当于把(l,r)区间空了出来,用h[r]减去提高后的h[l-1]自然就得到了h[r-l]