哈希算法

2019.\07.\02

哈希算法(Hash)

通过一个哈希函数H,将一种数据转化为能够用变量表示或是直接就可作为数组下标的数,通过哈希函数转化得到的数值我们称之为哈希值。

字符串Hash

寻找长度为n的主串S中的匹配串T(长度为m)出现的位置或次数的问题属于字符串匹配问题.
1. 朴素算法\(O(m)\)
枚举所有起始位置,直接检查是否匹配
2. 字符串Hash
比较长度为m的主串S的子串的哈希值与T的哈希值是否相等
(注:其实后面学的KMP可以解决大部分字符串Hash问题,但“从主串中选出两子串判断是否匹配”的问题例外)

一、求哈希值------滚动哈希

选取两互质常数b,h(b<h),假设字符串\(C=c_1c_2······c_m\)
定义哈希函数\(H(C)=(c_1b^{m-1}+c_2b^{m-2}+···+c_mb^0)modh\)
(相当于把字符串看作b进制数)
设H(C,k)为前k个字符构成字符串的哈希值
则:\(H(C,k+1)=H(C,k)*b+C_{k-1}\)

例如C="ACDA"(A->1,B->2)
\(H(C,1)=1\)
\(H(C,2)=1*b+3\)
\(H(C,3)=1*b^2+3*b+4\)
\(H(C,4)=1*b^3+3*b^2+4*b+1\)
因此任意字符\(C'=c_{k+1}c_{k+2}···c_{k+n}\)的哈希值为
\(C=c_1c_2···c_m\)

\[H(C')=H(C,k+n)-H(C,k)*b^n \]

那么只要预求得\(b^n\),就可用\(O(1)\)得任意字符串的子串哈希值
整个算法时间复杂度为\(O(n+m)\)
[!在实现算法时,利用32或64位无符号整数计算哈希值,取\(h=2^{32}\)\(2^{64}\)实现自然溢出取模。]

二、字符串Hash的正确性

常常认为竞赛题目不会出现不同的字符串哈希值相等的情况。实际上根据生日悖论,对于哈希值在\([0,n)\)内均匀分布的哈希函数出现不同字符哈希值相等的期望步数是\(O(sqrt(n))\).
什么是生日悖论?

措施:

用“双哈希”降低概率,取不同模数,把不同模数算出的哈希值记下来,只有几个哈希值都满足条件才判定字符串匹配。
(分别取\(h=10^9+7\)\(h=10^9+9\),就几乎不可能发生冲突,因为它们是一对“孪生质数”。)
什么是孪生质数?

posted @ 2019-07-02 11:39  HHHG  阅读(506)  评论(0编辑  收藏  举报