字符串哈希
哈希又称散列,是把一个对象通过哈希函数映射成一个整数值(哈希值)
设字符串为s,s[i]表示i位置字符的ASCII码,hash[i]表示字符串s的子串,前缀i的哈希值。
字符串哈希的常用哈希函数为:
hash[i]=hash[i−1]∗p+s[i]
(p通常为质数,可以进一步减少哈希冲突)也可写作:
hash[i]=i=0∑l−1s[i]∗pi
这个哈希函数对子串的运算非常友好,有下面一个重要性质:

显然,如果要求字符串s的子串s3s4的哈希值。由公式2可知s3s4的哈希值应该是s3*p+s4,显然不能直接用hash[4]-hash[2]得到s3s4的哈希值,而是应当使用hash[4]-hash[2]*p2。
所以可以推理出求子串s[l,r]哈希值公式应该为:
hash[l,r]=hash[r]−hash[l]∗pr−l+1
这可以用于字符串的模式匹配,例如:
给定一个模式串t,一个带匹配串s,问带匹配串s是否包含串t作为子串。
由公式2可知,模式串t的哈希值
hash[i]=i=0∑l−1s[i]∗pi
这是一个可以被计算出来的固定值,再把它与待匹配串s等长的所有子串的哈希值进行比较。
那么如何计算待匹配串s等长的所有子串的哈希值呢?
也非常简单,可以直接根据公式2求,也可以根据公式3如下推导
hash[l+1,r+1]=hash[r+1]−hash[l+1]∗pr−l+1
通过公式3展开后,再用公式3分别展开(看上面的图就明白了)
hash[r+1]就相当于hash[r]*p+s[r+1]
=(hash[r]∗p+s[r+1])−(hash[l]∗p+s[l+1])∗pr−l+1
然后合并,括号内可以凑出逆向公式3式子
=p∗(hash[r]−hash[l]∗pr−l+1)+s[r+1]−s[l+1]∗pr−l+1
=p∗hash[l][r]+s[r+1]−s[l+1]∗pr−l+1
最后结论:
hash[l+1,r+1]=p∗hash[l][r]+s[r+1]−s[l+1]∗pr−l+1
这意味着子串[l+1,r+1]的哈希值可以直接由子串[l,r]与s[l+1]、s[r+1]算出来,复杂度是O(1),而不需要通过公式2遍历一次s的子串。
这样即使把所有子串全部算出来也只有O(n)的复杂度。
参考:https://blog.csdn.net/pengwill97/article/details/80879387