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

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: [算法] 字符串 | 字符串哈希理论基础

字符串哈希简介

  • 字符串哈希,就是将不同的字符串映射成不同的整数。
  • 字符串哈希可以用于快速判断两个字符串是否相等,因为我们不需要逐个遍历比较两个字符串中的每个字符,只需要比较两个字符串映射成的哈希值是否相等即可。
  • 字符串哈希中,字符串与字符串对应的哈希值之间的映射关系称为哈希函数,通过哈希函数,我们可以计算出字符串对应的哈希值。
  • 哈希函数通常采用多项式哈希函数,设要计算哈希值的字符串的长度为 n,且该字符串为 S = s 1 s 2 s 3 . . . s n S = s_1s_2s_3...s_nS=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(modM) ,其中,s [ i ] s[i]s[i] 一般为字符串中字符 s i s_isi 对应的 ASCII 值,一般情况下,对于 p 与 M 的取值只要保证 p 与 M 互质即可,其中 p 小于 M,p 与 M 尽可能取大(可以避免哈希碰撞)。
  • 如果两个不同的字符串,通过哈希函数计算出来的哈希值相同,称为哈希碰撞。

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

  • 我们先模拟一遍使用哈希函数求字符串对应的哈希值的过程。
  • 这里以单哈希法为例,求字符串 “ABCDE” 的哈希值。
字符串 哈希值
h 0 = 0 h_0 = 0h0=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 Mh1=(97×p0)modM=(h0×p+97)modM
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 Mh2=(97×p1+98×p0)modM=(h1×p+98)modM
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 Mh3=(97×p2+98×p1+99×p0)modM=(h2×p+99)modM
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 Mh4=(97×p3+98×p2+99×p1+100×p0)modM=(h3×p+100)modM
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 Mh4=(97×p4+98×p3+99×p2+100×p1+101×p0)modM=(h4×p+101)modM
  • 由上表,求一个字符串的哈希值相当于求前缀和
  • 求一个字符串的哈希值,可以由该字符串除去最后一个字符的子串的哈希值乘上 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 Mh[i]=(h[i1]×p+s[i])modM

字符串子串哈希值的求解

  • 在上文中,我们已经可以求出一个字符串以字符串中各字符 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 MhCD=(99×p1+100×p0)modM
  • 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 MhCD=[97×p3+98×p2+99×p1+100×p0(97×p1+98×p0)×p2]modM
  • h C D = h A B C D − h A B × p 2 h_{CD} = h_{ABCD} - h_{AB} \times p^2hCD=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
相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
29天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
3月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
1月前
|
算法
两个字符串匹配出最长公共子序列算法
本文介绍了最长公共子序列(LCS)问题的算法实现,通过动态规划方法求解两个字符串的最长公共子序列,并提供了具体的编程实现细节和示例。
75 1
两个字符串匹配出最长公共子序列算法
|
1月前
|
存储 算法 C#
C#哈希查找算法
C#哈希查找算法
|
1月前
|
算法
第七章 回溯算法理论基础
第七章 回溯算法理论基础
16 0
|
1月前
|
算法
第四章 KMP算法理论基础
第四章 KMP算法理论基础
18 0
|
1月前
|
算法 安全 Go
Python与Go语言中的哈希算法实现及对比分析
Python与Go语言中的哈希算法实现及对比分析
40 0
|
1月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
3月前
|
算法 安全 JavaScript
安全哈希算法:SHA算法
安全哈希算法:SHA算法
53 1
安全哈希算法:SHA算法
|
3月前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。