定义

  • 字符串匹配-有效偏移
    字符串匹配问题就是找到所有的有效偏移
    如果P在T中以偏移s出现,那么称s是有效偏移。
    Introduction to Algorithm U32字符串匹配
  • 时间
    后面要介绍的算法,都基于模式进行了预处理,然后找到所有有效偏移,第二步被称为匹配。
    预处理时间和匹配时间如下:
    Introduction to Algorithm U32字符串匹配
  • 符号
    • 长度,连结Introduction to Algorithm U32字符串匹配
    • 前缀
      Introduction to Algorithm U32字符串匹配Introduction to Algorithm U32字符串匹配
    • 后缀
      Introduction to Algorithm U32字符串匹配
    • 符号的记忆trick:可以看竖线的位置,竖线在前为前缀,在后为后缀。
      ab是abcca的前缀,cca是abcca的后缀。空串是任何字符串的前缀和后缀。
      Introduction to Algorithm U32字符串匹配

1. 朴素字符串匹配算法

Naive-String-Matcher
Introduction to Algorithm U32字符串匹配
伪代码:Introduction to Algorithm U32字符串匹配

  • 可以看做是模式沿文本滑动,检测是否对应字符相等。
    Introduction to Algorithm U32字符串匹配
  • 时间复杂度:
    最坏的情况下,朴素字符串匹配算法运行时间为O((n-m+1)m),即在最后一个偏移时才匹配到,一共n-m+1个偏移,每个偏移还都要做一个m次的循环去检测对应字符是否相等。所以运行时间为O((n-m+1)m)。
  • 问题:忽视了检测无效s值时获得的文本信息。朴素的字符串匹配算法为什么慢? 因为它太健忘了,前一次匹配的信息其实可以有部分可以应用到后一次匹配中的,而朴素的字符串匹配算法只是简单的把这个信息扔掉,从头再来,因此,浪费了时间。好好的利用这些信息,自然可以提高运行速度。

2. Rabin-Karp算法

Introduction to Algorithm U32字符串匹配
算法原理:
Introduction to Algorithm U32字符串匹配

  • 首先对每个偏移下的窗口的中的数字取模,也就是分别计算
    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足够大,那么这种伪命中点可以尽量少出现,从而使额外测试的代价降低。
    Introduction to Algorithm U32字符串匹配Introduction to Algorithm U32字符串匹配
  • 那么怎么利用前一个窗口的信息呢?
  • 已知前一个窗后的值如何在常数时间内计算出某个窗口的值?
    • 第一个窗后的值为31415,去除最高位,然后乘以10(也就是左移一位),然后加入低位数字2得到14152,也就是下一个窗口的值。
  • 伪代码
    Introduction to Algorithm U32字符串匹配
  • 复杂度分析
    ……没看懂……

Introduction to Algorithm U32字符串匹配
Introduction to Algorithm U32字符串匹配

3. 利用有限自动机进行字符串匹配

自动机:只对每个文本字符检查一次,并且检查每个文本字符所用时间为常数。因此模式预处理完成并建立好自动机后进行匹配所需要的时间为O(n)。
但是如果n很大,建立自动机所需的时间也可能很多。

4. Knuth-Morris-Pratt(KMP)算法

相关文章: