字符串哈希

原文链接:OIwiki

Hash的思想

核心思想

Hash 的核心思想在于,将输入映射到一个值域较小、可以方便比较的范围。

定义

我们定义一个把字符串映射到整数的函数 f ,这个 f 称为 Hash 函数。

通常我们采用的是多项式 Hash 的方法,对于一个长度为l的字符串s来说,我们可以这样定义多项式 Hash 函数:f(s) =∑li=1s[i]×bi-1(mod M),例如,对于字符串xyz,其哈希函数值为xb2+yb+z

多次询问子串哈希

单次计算一个字符串的哈希值的复杂度是O (n)

如果要多次询问字符串的子串的哈希值,我们可以预处理出每个前缀的哈希值。

f i(s)表示字符串的长度为i的前缀的哈希值,不难得到f i (s) = f i-1(s) ∗ b + s[i]。

现在,我们想要快速求出f (s[l...r]),按照定义有字符串s[l...r]的哈希值为

f (s[l...r]) = s[l] ∗ br-l + s[l +1] ∗ br-l-1 + ... + s[r - 1] ∗ b + s[r] =  f r(s) - f l-1 (s) ∗ br-l+1

于是,我们就能O (1)地回答每次询问

Hash的运用

字符串匹配

求出模式串的哈希值后,求出文本串每个长度为模式串长度的子串的哈希值,分别与模式串的哈希值比较即可。

 

允许k次失败的字符串匹配

问题:给定长为 s 的源串 ,以及长度为的模式串,要求查找源串中有多少子串与模式串匹配。s's匹配,当且仅当s's长度相同,且最多有k个位置字符不同。

 

我们可以枚举所有可能长度的子串,然后通过哈希+二分快速找到第一个失配的位置,然后将之前的部分删掉,继续查找下一个位置。这个过程最多发生k次。

时间复杂度为O(m + knlog2m)

最长回文子串

二分答案。对于一个长度k,枚举所有长度为k的子串,然后判断该子串两侧的哈希值是否相等即可·。

时间复杂度O(nlogn)

 

也可以O(n)地解决该问题,记Ri表示以i为结尾的最长回文的长度,由于Ri Ri-1 + 2,因此只需每次将长度从Ri-1 + 2开始递减,直到找到第一个回文为止。设当前枚举的最大长度为z,每次i增加时,z增加2,每次暴力循环z减小1,故暴力循环最多发生2n次,时间复杂度为O(n)

最长公共子字符串

问题:给定m个总长不超过n的非空字符串,查找所有字符串的最长公共子字符串,如果有多个,任意输出其中一个。

考虑二分答案。假设现在枚举的最大长度为k,check(k)的逻辑为求所有字符串的长度为k的子字符串的哈希值,然后求交集即可。

确定字符串中不同子字符串的数量

问题:给定长为n的字符串,仅由小写英文字母组成,查找该字符串中不同子串的数量。

遍历所有长度为l=1,2,...,n的子字符串,分别哈希即可。

 

posted @ 2022-01-26 16:30  Endergarten  阅读(270)  评论(0)    收藏  举报