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

本文涉及的产品
简介: [算法] 字符串 | 字符串哈希理论基础

字符串哈希简介

  • 字符串哈希,就是将不同的字符串映射成不同的整数。
  • 字符串哈希可以用于快速判断两个字符串是否相等,因为我们不需要逐个遍历比较两个字符串中的每个字符,只需要比较两个字符串映射成的哈希值是否相等即可。
  • 字符串哈希中,字符串与字符串对应的哈希值之间的映射关系称为哈希函数,通过哈希函数,我们可以计算出字符串对应的哈希值。
  • 哈希函数通常采用多项式哈希函数,设要计算哈希值的字符串的长度为 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
相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
3天前
|
存储 算法 Java
Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。
【6月更文挑战第21天】Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。简单哈希表实现未涵盖冲突解决和删除操作。
10 1
|
10天前
|
存储 算法 关系型数据库
【MySQL技术内幕】5.7- InnoDB存储引擎中的哈希算法
【MySQL技术内幕】5.7- InnoDB存储引擎中的哈希算法
14 1
|
11天前
|
存储 算法 Java
哈希算法篇 - 布隆过滤器
哈希算法篇 - 布隆过滤器
13 1
|
14天前
|
算法 数据挖掘 开发者
LeetCode题目55:跳跃游戏【python5种算法贪心/回溯/动态规划/优化贪心/索引哈希映射 详解】
LeetCode题目55:跳跃游戏【python5种算法贪心/回溯/动态规划/优化贪心/索引哈希映射 详解】
|
18天前
|
存储 算法 NoSQL
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
19 1
|
18天前
|
存储 算法 Cloud Native
C++ bcrypt算法 字符串加密,亲测有效
C++ bcrypt算法 字符串加密,亲测有效
|
18天前
|
存储 NoSQL 算法
Redis集群,集群的概念 三种主流分片方式1.哈希求余 一致性哈希算法:方案三:哈希槽分区算法问题一Redis集群是最多有16384个分片吗问题二:为什么是16384个,集群扩容:1.新的主节点
Redis集群,集群的概念 三种主流分片方式1.哈希求余 一致性哈希算法:方案三:哈希槽分区算法问题一Redis集群是最多有16384个分片吗问题二:为什么是16384个,集群扩容:1.新的主节点
|
18天前
|
存储 算法
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
|
29天前
|
算法
KPM算法求字符串的最小周期证明
公式 `ans = n - LPS[n-1]` 描述了最小周期,其中 `n` 是子串长度,`LPS[n-1]` 是前缀函数值。证明分为特殊情况和一般情况:对于完整周期字符串,`LPS[n-1] = 3*T`,故 `ans = T`;对于非完整周期,通过分析不同长度的 `[末部分]` 和 `[前部分]`,展示 `ans` 始终等于周期 `T` 或由 `[e][b]` 构成的最小周期,从而证明公式正确。
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串