算法导论【字符串匹配】—朴素算法、Rabin Karp、有限自动机、KMP
- 朴素字符串匹配算法
- Rabin-Karp算法
- 有限自动机
- KMP算法
朴素字符串匹配算法
- 预处理时间:0
- 匹配时间:O((n-m+1)m)
Rabin-Karp算法
- 预处理时间:Θ(m),需要预先算出匹配串的哈希值
- 匹配时间:O((n−m+1)m),匹配过程与朴素算法类似,但是不需要逐个比对,先比对哈希值,这样可以减少字符匹配次数,计算待匹配的m个字符的哈希值,采用特定方法可以只要常数时间
- Rabin-Karp算法的预处理时间为 Θ ( m ) \Theta(m) Θ(m),在最坏情况下,运行时间为 Θ ( ( n − m + 1 ) m ) \Theta((n-m+1)m) Θ((n−m+1)m)
- Rabin-Karp算法比较字符串的哈希值,而不是字符串本身。为了提高效率,可以从当前位置的哈希值轻松计算文本中下一个位置的哈希
- 简单说就是:每次计算m个字符的字符串的哈希值,然后与匹配串的哈希值对比,如果不相等那这两个字符串肯定不一样,如果哈希值相等,那么再逐个匹配字符,这样可以减少不必要的匹配
- 如果哈希值不相等,算法将计算下一个M字符序列的哈希值。如果哈希值相等,算法将比较模式和M字符序列。这样,每个文本子序列只有一个比较,只有当哈希值匹配时才需要字符匹配
- Rabin Karp算法的预处理阶段包括计算哈希 H a s h ( P ) Hash(P) Hash(P)。它可以在恒定的空间和 O ( m ) O(m) O(m)时间内完成。
- 在搜索阶段,将哈希 H a s h ( P ) Hash(P) Hash(P)与哈希 H a s h ( T [ j . . j + m − 1 ] ) Hash(T[j..j+m−1]) Hash(T[j..j+m−1])比较就足够了。如果找到了一个等式,仍然需要逐个字符检查等式 P = T [ j . . j + m − 1 ] P=T[j..j+m−1] P=T[j..j+m−1]。
- Rabin Karp算法的时间复杂度为 Θ ( ( n − m + 1 ) m ) = Θ ( m n ) Θ((n−m+1)m)=Θ(mn) Θ((n−m+1)m)=Θ(mn)(例如,当在n中搜索m时)。当有效点很小时,例如 O ( 1 ) O(1) O(1),其预期的文本字符比较数为 O ( n + m ) = O ( n ) O(n+m)=O(n) O(n+m)=O(n)。
有限自动机
- 预处理时间:O(|mΣ|),|Σ|为待匹配串的字母表大小
- 匹配时间:Θ(n),预处理完后只需要扫描一遍字符串即可找到匹配串
KMP算法
-
预处理时间:Θ(m)
-
匹配时间:Θ(n)
-
关键在于计算出前缀 π \pi π数组, π \pi π就是文本串中在该位置能够得到最长的前后缀长度,举个例子:
-
预处理过程:- 匹配过程: