定义
- 字符串匹配-有效偏移
字符串匹配问题就是找到所有的有效偏移。
如果P在T中以偏移s出现,那么称s是有效偏移。
- 时间
后面要介绍的算法,都基于模式进行了预处理,然后找到所有有效偏移,第二步被称为匹配。
预处理时间和匹配时间如下:
- 符号
- 长度,连结
- 前缀
- 后缀
- 符号的记忆trick:可以看竖线的位置,竖线在前为前缀,在后为后缀。
ab是abcca的前缀,cca是abcca的后缀。空串是任何字符串的前缀和后缀。
- 长度,连结
1. 朴素字符串匹配算法
Naive-String-Matcher
伪代码:
- 可以看做是模式沿文本滑动,检测是否对应字符相等。
- 时间复杂度:
最坏的情况下,朴素字符串匹配算法运行时间为O((n-m+1)m),即在最后一个偏移时才匹配到,一共n-m+1个偏移,每个偏移还都要做一个m次的循环去检测对应字符是否相等。所以运行时间为O((n-m+1)m)。 - 问题:忽视了检测无效s值时获得的文本信息。朴素的字符串匹配算法为什么慢? 因为它太健忘了,前一次匹配的信息其实可以有部分可以应用到后一次匹配中的,而朴素的字符串匹配算法只是简单的把这个信息扔掉,从头再来,因此,浪费了时间。好好的利用这些信息,自然可以提高运行速度。
2. Rabin-Karp算法
算法原理:
- 首先对每个偏移下的窗口的中的数字取模,也就是分别计算
23590%13=8
35902%13=9
59023%13=3
……
最后得到8 9 3 11 0 ……7 9 11 - 计算模式取模后的结果,如P=31415,P%13=7,所以在计算的mod13后的结果中寻找结果为7的窗口,找到了两个,s=6,s=12。然后对于命中的窗口进行重新检验,对应位置相同则为真正出现,否则为伪命中。如果模q足够大,那么这种伪命中点可以尽量少出现,从而使额外测试的代价降低。
- 那么怎么利用前一个窗口的信息呢?
- 已知前一个窗后的值如何在常数时间内计算出某个窗口的值?
- 第一个窗后的值为31415,去除最高位,然后乘以10(也就是左移一位),然后加入低位数字2得到14152,也就是下一个窗口的值。
- 伪代码
- 复杂度分析
……没看懂……
3. 利用有限自动机进行字符串匹配
自动机:只对每个文本字符检查一次,并且检查每个文本字符所用时间为常数。因此模式预处理完成并建立好自动机后进行匹配所需要的时间为O(n)。
但是如果n很大,建立自动机所需的时间也可能很多。