[算法] 字符串 | 字符串哈希理论基础

字符串哈希简介

  • 字符串哈希,就是将不同的字符串映射成不同的整数。
  • 字符串哈希可以用于快速判断两个字符串是否相等,因为我们不需要逐个遍历比较两个字符串中的每个字符,只需要比较两个字符串映射成的哈希值是否相等即可。
  • 字符串哈希中,字符串与字符串对应的哈希值之间的映射关系称为哈希函数,通过哈希函数,我们可以计算出字符串对应的哈希值。
  • 哈希函数通常采用多项式哈希函数,设要计算哈希值的字符串的长度为 n,且该字符串为 S = s 1 s 2 s 3 . . . s n S = s_1s_2s_3...s_n S=s1s2s3...sn,则哈希函数为 h ( S ) = ∑ i = 1 n s [ i ] × p n − i ( m o d   M ) h(S) = \sum_{i=1}^{n} s[i] \times p^{n-i} (mod \space M) h(S)=i=1ns[i]×pni(mod M) ,其中, s [ i ] s[i] s[i] 一般为字符串中字符 s i s_i si 对应的 ASCII 值,一般情况下,对于 p 与 M 的取值只要保证 p 与 M 互质即可,其中 p 小于 M,p 与 M 尽可能取大(可以避免哈希碰撞)。
  • 如果两个不同的字符串,通过哈希函数计算出来的哈希值相同,称为哈希碰撞。

字符串哈希值求解过程模拟

  • 我们先模拟一遍使用哈希函数求字符串对应的哈希值的过程。
  • 这里以单哈希法为例,求字符串 “ABCDE” 的哈希值。
字符串哈希值
h 0 = 0 h_0 = 0 h0=0
A h 1 = ( 97 × p 0 ) m o d   M = ( h 0 × p + 97 ) m o d   M h_1 = (97 \times p^0) mod \space M = (h_0 \times p + 97)mod \space M h1=(97×p0)mod M=(h0×p+97)mod M
AB h 2 = ( 97 × p 1 + 98 × p 0 ) m o d   M = ( h 1 × p + 98 ) m o d   M h_2 = (97 \times p^1 + 98 \times p^0) mod \space M = (h_1 \times p + 98)mod \space M h2=(97×p1+98×p0)mod M=(h1×p+98)mod M
ABC h 3 = ( 97 × p 2 + 98 × p 1 + 99 × p 0 ) m o d   M = ( h 2 × p + 99 ) m o d   M h_3 = (97 \times p^2 + 98 \times p^1 + 99 \times p^0) mod \space M = (h_2 \times p + 99)mod \space M h3=(97×p2+98×p1+99×p0)mod M=(h2×p+99)mod M
ABCD h 4 = ( 97 × p 3 + 98 × p 2 + 99 × p 1 + 100 × p 0 ) m o d   M = ( h 3 × p + 100 ) m o d   M h_4 = (97 \times p^3 + 98 \times p^2 + 99 \times p^1 + 100 \times p^0) mod \space M = (h_3 \times p + 100)mod \space M h4=(97×p3+98×p2+99×p1+100×p0)mod M=(h3×p+100)mod M
ABCDE h 4 = ( 97 × p 4 + 98 × p 3 + 99 × p 2 + 100 × p 1 + 101 × p 0 ) m o d   M = ( h 4 × p + 101 ) m o d   M h_4 = (97 \times p^4 + 98 \times p^3 + 99 \times p^2 + 100 \times p^1 + 101 \times p^0) mod \space M = (h_4 \times p + 101)mod \space M h4=(97×p4+98×p3+99×p2+100×p1+101×p0)mod M=(h4×p+101)mod M
  • 由上表,求一个字符串的哈希值相当于求前缀和
  • 求一个字符串的哈希值,可以由该字符串除去最后一个字符的子串的哈希值乘上 p ,在加上最后一个字符的 ASCII 值模 M 得到,即 h [ i ] = ( h [ i − 1 ] × p + s [ i ] ) m o d   M h[i] = (h[i-1] \times p + s[i])mod \space M h[i]=(h[i1]×p+s[i])mod M

字符串子串哈希值的求解

  • 在上文中,我们已经可以求出一个字符串以字符串中各字符 s[i] 结尾的子串的哈希值
  • 那么,我们是否可以利用求出的以字符串中各字符 s[i] 结尾的子串的哈希值来求字符串任一子字符串的哈希值,答案是可以的。
  • 如,我们要求字符串 “ABCDE” 的子字符串 “CD” 的哈希值
  • h C D = ( 99 × p 1 + 100 × p 0 ) m o d   M h_{CD} = (99 \times p^1 + 100 \times p^0) mod \space M hCD=(99×p1+100×p0)mod M
  • h C D = [ 97 × p 3 + 98 × p 2 + 99 × p 1 + 100 × p 0 − ( 97 × p 1 + 98 × p 0 ) × p 2 ] m o d   M h_{CD} = [97 \times p^3 + 98 \times p^2 + 99 \times p^1 + 100 \times p^0 - (97 \times p^1 + 98 \times p^0) \times p^2] mod \space M hCD=[97×p3+98×p2+99×p1+100×p0(97×p1+98×p0)×p2]mod M
  • h C D = h A B C D − h A B × p 2 h_{CD} = h_{ABCD} - h_{AB} \times p^2 hCD=hABCDhAB×p2
  • 字符串 “ABCDE” 中 ‘D’ 的下标为 4,‘C’ 的下标为 3
  • 所以可以令字符串 “ABCDE” 的子字符串 “CD” 的哈希值表示为 h C D = h [ 3 , 4 ] = h [ 4 ] − h [ 3 − 1 ] × p 4 − 3 + 1 h_{CD} = h[3, 4] = h[4] - h[3 - 1] \times p^{4 - 3 + 1} hCD=h[3,4]=h[4]h[31]×p43+1
  • 因此,字符串任一子字符串的哈希值为 h [ l , r ] = h [ r ] − h [ l − 1 ] × p r − l + 1 h[l, r] = h[r] - h[l-1] \times p^{r - l + 1} h[l,r]=h[r]h[l1]×prl+1
  • 求一个字符串的子字符串的哈希值相当于求区间和。

字符串哈希方法

自然溢出法

  • 自然溢出法,如,在C++中,可以将哈希函数的函数值的类型定义为 unsigned long long,我们只需指定 p 取何值即可,当字符串计算出来的哈希值大于 unsigned long long 时,就会产生无符号长整数的自然溢出,相当于计算出来的哈希值自动对 2 64 2^{64} 264 进行取模运算

单哈希法

  • 单哈希法,就是只使用一个哈希函数,只指定一个 p 值和一个 M 值,使用这个哈希函数计算出来的哈希值作为字符串的哈希值。

双哈希法

  • 双哈希法,就是使用两个两个哈希函数,指定两个 p 值和两个 M 值,使用这两个哈希函数分别计算字符串的哈希值,最终使用两个哈希函数计算出来的哈希值组成的数对作为字符串的哈希值。
  • 当然,你也可以使用多个不同的哈希函数,使用这若干个哈希函数分别计算字符串的哈希值,最终使用这若干个哈希函数计算出来的哈希值组成的元组作为字符串的哈希值。
  • 但是使用两个哈希值组成的二元组就基本上避免了哈希碰撞,且使用多元组会消耗更多的时间,所以一般双哈希法就足够了。

三种哈希方法的比较

  • 从速度上来看,自然溢出法快于单哈希法,单哈希法快于双哈希法。
  • 从安全上来看,双哈希法发生哈希碰撞的概率小于单哈希法,即双哈希法比单哈希法安全,而单哈希法和自然溢出法的安全性主要取决于 p 和 M 的取值。
  • 自然溢出法其实可以看成是单哈希法的特殊情况,M 的取值固定为 2 64 2^{64} 264
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在C++中,可以使用字符串哈希算法来加速字符串的比较操作。 引用\[1\]中的代码示例展示了一个使用字符串哈希算法的C++代码。该代码使用了前缀和数组和字符串数组来存储字符串,并通过计算哈希值来比较两个子串是否相等。其中,哈希值的计算使用了前缀和数组和幂运算。 引用\[2\]中的解释指出,使用字符串哈希的目的是为了比较字符串时不直接比较字符串本身,而是比较它们对应映射的数字。这样可以将子串的哈希值的时间复杂度降低到O(1),从而节省时间。 引用\[3\]中的代码示例也展示了一个使用字符串哈希算法的C++代码。该代码使用了前缀和数组和字符串数组来存储字符串,并通过计算哈希值来比较两个子串是否相等。与引用\[1\]中的代码类似,哈希值的计算也使用了前缀和数组和幂运算。 综上所述,字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在C++中,可以使用前缀和数组和幂运算来计算字符串哈希值,并通过比较哈希值来判断两个子串是否相等。 #### 引用[.reference_title] - *1* [C++算法题 # 33 字符串哈希](https://blog.csdn.net/weixin_44536804/article/details/123425533)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [字符串哈希(c++)](https://blog.csdn.net/qq_41829492/article/details/120980055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [AcWing 841. 字符串哈希(C++算法)](https://blog.csdn.net/YSA__/article/details/108453403)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值