字符串匹配——Rabin–Karp algorithm

        在https://mp.csdn.net/postedit/84679263这篇使用的是朴素的字符串匹配方法,算法复杂度为O(mn)(m为模式串长度,n为文本串长度)。在字符串匹配任务中,Rabin–Karp算法通过hash函数试图加速文本子串与模式串的匹配过程的“逐一比对过程”

       这里的hash函数可以将每个子串转化为一个数值,因为存在这样一个事实:如果两个字符串是相等的,则哈希(函数)值相等,字符串匹配问题也就被归化为“计算模式串的哈希值,然后在文本串中寻找相等哈希值的子串”的问题。

       然而问题来了,一些不同的字符串可能有相同的哈希值,相同的哈希值的两字符串可能不匹配,因此文本串中“潜在的匹配字符串”与模式串还需要一一比对来再次确认,那么对于越长的“潜在匹配子字符串”需要花费更多的时间来再次确认。

伪代码如下:

1 	RabinKarpSearch(string s[1..n], string pattern[1..m])
2		hpattern := hash(pattern[1..m]);     		O(m)
3			for i from 1 to n-m+1
4				hs := hash(s[i..i+m-1])				O(m)
5				if hs = hpattern						O(n)
6					if s[i..i+m-1] = pattern[1..m]		O(m)
7						return i
8		return not found

       第五行要执行n-m+1次,每次比较都是O(1)。朴素的计算字符串S[i+1…i+m]哈希值的方法需要O(m)次,因为哈希值计算在每次循环中都要进行,朴素哈希计算方法需要O(mn)次,为了加速整个算法,哈希值计算必须变成常数时间内完成,一个小技巧就是变量hs已经包含先前字符串s[i..i+m-1]的哈希值。如果这个值被用来在常数时间内计算下一个字符串的哈希值,那么连续计算哈希值就非常的快,可以使用rolling hash来实现这一想法,一个简单的但不是很好的rolling hash 函数仅仅加上子串中每个字符的值:hash(s[i+1…i+m])=hash(s[i…i+m-1])-s[i]+s[i+m],这个简单的函数计算哈希值使得产生哈希碰撞的概率提高从而导致line5执行较多,好的性能需要良好的哈希函数来减少line5的执行,因为逐个字符的比对需要O(m)次,整个算法的最坏执行复杂度为O(mn)。所以这个hash函数的设计关乎整个算法的性能

下面介绍一种哈希函数,它将每个字符串视作以某个很大的素数为基的数

比如基底是256,素数模是101,字符串’hi’(104,105)的哈希值计算为:

                                                  

       因为这个算法的最坏复杂度O(mn),单个字符串的匹配性能劣于KMP算法和BM算法,然而在多字符串匹配应用上表现很好。为了在文本串中寻找k(一个较大的数字)个定长(长度都为m)模式串,RK算法的一个变体使用一个布隆过滤器或者集合数据结构来检查:给定字符串的哈希值是否属于“模式串哈希值集合”(要寻找的模式串们)。

伪代码如下:

                                      

扫描二维码关注公众号,回复: 4422945 查看本文章

       解释一下,该算法先将目标模式串们插入集合中,然后从文本串逐一进行计算子串S[i:i+m-1]的哈希值,如果哈希值相等并且该串存在目标字符串们的集合中则匹配成功一个目标字符串。原理比较简单,下一步就是来实现这个算法。

参考文献:

https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm

《The Introduction to Algorithms》

猜你喜欢

转载自blog.csdn.net/To_be_to_thought/article/details/84890018