字符串Hash
什么是字符串Hash?
字符串Hash可以通俗的理解为,把一个字符串转换为一个整数。
如果我们通过某种方法(映射函数),将字符串转换为一个整数,这个映射函数不一定是单射函数,但是我们能尽量的选取一些参数(p和模数mod)来使得在该场景下尽量是一个单射函数。
如果有两个不同的字符串映射为一个同样的整数,这就产生了hash冲突。
所以问题就是如何构造这个Hash函数,使得他们成为一个单射(不存在hash冲突) 。不用担心,接下来的内容正要讲解。
Hash函数
给定一个字符串 S=s1s2s3..sn,对字母 x,我们规定 idx(x)=x−′a+1。 (当然也可以直接用si的ASCII值)
hash函数有许多,这里只介绍常用的BKDR Hash函数
更多hash函数请参考http://blog.chinaunix.net/uid-15014334-id-5612796.html
BKDR Hash函数:
hash[1]=idx(s1) ,在模mod下
hash[i]=hash[i−1]∗p+idx(si) ,在模mod下
其中p和mod都是我们指定的参数,一般情况下将p和mod尽量取大即可,这样冲突的概率是很低的。
举例:
如取p=13,mod=101,对字符串abc进行Hash
hash[0] = 1
hash[1] = (hash[0] * 13 + 2) % 101 = 15
hash[2] = (hash[1] * 13 + 3) % 101 = 97
都有哪些Hash方法?
普通单Hash方法
只选取一个hash值用来表示一个字符串
自然溢出方法
我们可以将hash[] 的类型定为unsigned long long ,也就是 264−1。并且我们选取$2^{64}-1 $为模数,这样不用每次都进行取模操作( 溢出自动取模) 。这在Acm解决问题是常见的。
双Hash方法
将一个字符串用不同的 mod hash两次,将这两个结果用一个二元组表示,作为Hash结果。
双hash方法下hash冲突的概率是很低的。
BKDR Hash函数怎么O(1)获得子串的hash值?
假设有一|S|=5的字符串,设Si为第i个字符,其中1≤i≤5。
根据定义分别求出hash[i]
hash[1]=s1
hash[2]=s1∗p+s2
hash[3]=s1∗p2+s2∗p+s3
hash[4]=s1∗p3+s2∗p2+s3∗p+s4
hash[5]=s1∗p4+s2∗p3+s3∗p2+s4∗p+s5
假设我们现在想获得字串 s3s4的hash值,简单计算我们可以知道 s3s4的hash值为 s3∗p+s4, 我们再看下上面列出来的公式,咦~,这不是hash[4]的后缀吗!该后缀前面的部分是 hash[2]∗p2 ! ,为此我们发现所有的子串都可以按照这样的方式得出该字串的hash值。
为此我们得出子串 si..sj 的hash值为: hash[j]−hash[i−1]∗pj−i+1.
当然因为减法可能会出现负数,为了一致我们将统一处理: ((hash[j]−hash[i−1]∗pj−i+1)%mod+mod)%mod
字符串Hash的应用
该部分参考博客https://blog.csdn.net/pengwill97/article/details/80879387#字符串hash入门 ,但是解决方案处不同
题型一
描述
问题:
给两个字符串S1,S2,求S2是否是S1的子串,假设S1的长度为n,S2的长度为为m,求S2在S1中出现的次数
数据范围:1=<|S1|,|S2|<=10000
解法:
可以考虑计算出字符串 s1和 s2的hash数组,然后O(n)处理出所有 s1长度的 s2子串,如果一个子串的hash值与 s2的hash值相等,就判定该子串与 s2相等。总的时间复杂度为O(n+m)。(说实话这是kmp模板题)
题型二
描述
问题:给N个单词串,和一个文章串,求每个单词串是否是文章串的子串,并求每个单词在文章中出现的次数。
数据范围:文章串长度:[1, 105],N个单词串总长:[1, 106]
解法
其实这是一个AC自动机模板题。
题型三
描述
问题:给两个字符串S1,S2,假设S1的长度为n,S2的长度为为m,求它们的最长公共子串的长度。
数据范围:1=<|S1|,|S2|<=10^5
解法:
考虑二分最长公共字符串长度,对于每一个二分的字符串长度假设为ls,接下来求出 s2的所有长度为ls的子串的hash值并放在map中,这个时间复杂度是O(mlogm),然后求出 s1的所有长度为ls的子串,这个时间复杂度为O(n),如果有一个子串的hash值在map中出现过,证明他们有一个长度为ls的公共子串,就向大于ls的长度找答案。否则就没有出现过,答案比ls小。总的时间复杂度为O(log(min(n,m))*(n+m)logm) 。如果n等于m的话时间复杂度就是O(nlognlogn)
题型四
问题:给一个字符串S,求S的最长回文子串。
比如abcbbabbc的最长回文子串是cbbabbc,bbabb也是回文串,但不是最长的
数据范围: 1=<|S|<=10^5
<dl> <dt> 解法 </dt> <dd> manacher算法模板题目 </dd> </dl>