字符串匹配算法在文本文件中查找模式、DNA序列搜寻、网络引擎搜索中都有应用。
字符串匹配问题的形式化定义:假设文本是一个长为 nnn 的数组 T[1..n]T[1..n]T[1..n],而模式是一个长度为 mmm 的数组 P[1..m]P[1..m]P[1..m],其中 m≤nm \le nm≤n。字符数组 PPP 和 TTT 通常称为字符串。

如果 0≤s≤n−m0 \le s \le n-m0≤s≤n−m,并且 T[s+1..s+m]=P[1..m]T[s+1..s+m]=P[1..m]T[s+1..s+m]=P[1..m] (即如果 T[s+j]=P[j]T[s+j]=P[j]T[s+j]=P[j],其中 1≤j≤m1 \le j \le m1≤j≤m),那么称模式 PPP 在文本 TTT 中出现,其偏移为 sss。如果 PPP 在 TTT 中以偏移 sss 出现,则称 sss 为有效偏移,否则,称为无效偏移。
32.1节讲解朴素字符串匹配算法,32.2节讲解Rabin-Karp算法,32.3节讲解利用优先自动机进行字符串匹配,32.4节讲解Knuth-Morris-Pratt算法。
除了朴素算法外,其他字符串匹配算法都基于模式进行了预处理,然后找到所有有效偏移,我们称第二步为“匹配”。下表给出了每个算法的预处理时间和匹配时间。每个算法的总运行时间是预处理时间和匹配时间的和。
| 算法 | 预处理时间 | 匹配时间 |
|---|---|---|
| 朴素算法 | 000 | O((n−m+1)m)\Omicron((n-m+1)m)O((n−m+1)m) |
| Rabin-Karp算法 | Θ(m)\Theta(m)Θ(m) | O((n−m+1)m)\Omicron((n-m+1)m)O((n−m+1)m) |
| 有限自动机算法 | O(m∑)\Omicron(m\sum)O(m∑) | Θ(n)\Theta(n)Θ(n) |
| Knuth-Morris-Pratt | Θ(m)\Theta(m)Θ(m) | Θ(n)\Theta(n)Θ(n) |
符号和术语
- ∑∗\sum^*∑∗ 表示包含所有有限长度的字符串集合,∑\sum∑ 表示字母表;
- ∣x∣|x|∣x∣ 表示字符串 xxx 的长度;
- 两个字符串 xxx 和 yyy 的连结用 xyxyxy 表示,长度为 ∣x∣+∣y∣|x|+|y|∣x∣+∣y∣,由 xxx 的字符后接 yyy 的字符构成;
- 字符串 www 是字符串 xxx 的前缀,记作 w⊏xw \sqsubset xw⊏x;字符串 www 是字符串 xxx 的后缀,记作 w⊐xw \sqsupset xw⊐x;
- 空字符串 ε\varepsilonε 是任何一个字符串的前缀和后缀。
后缀重叠引理:假设 x,yx,yx,y 和 zzz 是满足 x⊐zx \sqsupset zx⊐z 和 y⊐zy \sqsupset zy⊐z 的字符串。如果 ∣x∣≤∣y∣|x| \le |y|∣x∣≤∣y∣,那么 x⊐yx \sqsupset yx⊐y;如果 ∣x∣≥∣y∣|x| \ge |y|∣x∣≥∣y∣,那么 y⊐xy \sqsupset xy⊐x;如果 ∣x∣=∣y∣|x| = |y|∣x∣=∣y∣,那么 x=yx = yx=y。

为了符号简单,我们把模式 P[1..m]P[1..m]P[1..m] 由前 kkk 个字符组成的前缀 P[1..k]P[1..k]P[1..k] 记作 PkP_kPk。因此 P0=ε,Pm=P=P[1..m]P_0=\varepsilon,P_m=P=P[1..m]P0=ε,Pm=P=P[1..m]。
32.1 朴素字符串匹配算法
朴素字符串匹配算法是通过一个循环找到所有有效偏移,判断条件为 P[1..m]=T[s+1..s+m]P[1..m] = T[s+1..s+m]P[1..m]=T[s+1..s+m],其中 sss 总共有 n−m+1n-m+1n−m+1 个可能的值。
NAIVE-STRING-MATCHER(T, P)
n = T.length
m = P.length
for s = 0 to n-m
if P[1..m] == T[s+1..s+m]
print "Pattern occurs with shift" s
朴素字符串匹配过程可以看作“模式”沿着“文本”滑动(偏移),每次偏移都要检测模式中的字符和文本中对应的字符是否相等。

在最坏情况下,朴素字符串匹配算法运行时间为 O((n−m+1)m)\Omicron((n-m+1)m)O((n−m+1)m)。偏移需要 n−m+1n-m+1n−m+1 次,每次偏移,都要将模式 PPP 中的 mmm 个字符进行比较。
32.2 Rabin-Karp算法
在实际应用中,Rabin-Karp所提出的字符串匹配算法能够较好的运行, 并且还可以从中归纳出相关问题的其他算法,比如二维模式匹配。Rabin-Karp算法的预处理时间为 Θ(m)\Theta(m)Θ(m),并且在最坏情况下,它的运行时间为 Θ((n−m+1)m)\Theta((n-m+1)m)Θ((n−m+1

文章介绍了几种常见的字符串匹配算法,包括朴素算法、Rabin-Karp算法、有限自动机和Knuth-Morris-Pratt(KMP)算法。朴素算法在最坏情况下的时间复杂度为O((n-m+1)m),而Rabin-Karp算法利用滚动哈希降低了比较次数。有限自动机通过预处理构建高效匹配机制,匹配时间复杂度为Θ(n)。KMP算法通过部分匹配表避免了文本串指针回退,提高了匹配效率。
最低0.47元/天 解锁文章
2506

被折叠的 条评论
为什么被折叠?



