【数据结构与算法】String-02 KMP和有限状态自动机
来源:《算法》第四版 第五章
文章目录
1、暴力字符匹配算法
public static int search(String pt, String txt){
int j, M = pat.length();
int i, N = txt.length();
for(i = 0, j = 0; i < N && j < M; i++){
if(txt.charAt(i) == pat.charAt(j)) j++;
else{ i -= j; j = 0;}
}
if(j == M) return i - M; //找到匹配
else return N; //未找到匹配
}
可以看到,第6句,每次匹配失败的时候,i 就会回退一些。这样在最坏的情况下,就造成了效率的低下。所以,我们不希望每一次 i 都回退到上一次匹配的开头,我们希望可以利用我们已经使用过的信息来完成回退的减少。
2、DFA考虑回退
和大多数的教程不同,大多数的教程是用 next[] 数组来运算和记录它的会退,而《算法》中,采用了更好理解的 DFA(deterministic finite automation,确定有限状态自动机),比如对于 pattern字串“ABABAC”,根据这个字串就能确认它所对应的自动机:
同时,它的 dfa[][] 也能很快的确定下来了,那根据我们画出的 自动状态机,我们去匹配各个字符串,以及清楚的知道它们的回退机制之后,我们就能很快的在 text字串 中开始O(N+M)复杂度的匹配了。
dfa[][] 第一个 [] 中填充的是,i 所指的字符在字母表中的序号,第二个 [] 是 j ,也就是 pattern 中的第几个字符。在这个例子中,pattern的长度为6,也就是当 j 达到 6 的时候就已经是 自动状态机的停止状态了。
3、构造DFA
当我们在匹配 i 指针 和 j 指针的字符的失败的时候,i 指针每次依然在前进,j 指针所执行的操作不像是回退,而更像是 状态自动机 中的状态重置。
所以,我们现在只考虑它的重启状态:我们在扫描当前的 字符的值 的之前,就已经可以通过之前的已知信息来知道:如果它失败了,它应当回退到什么位置去。

我们在以下的构造流程中,可以清楚的看到,模板 X 的走向会因为输入的变化而变化。
构造出来的感觉就比较像是 KMP中的next[]数组。它的构造过程就分为 3 个步骤:
① 将
dfa[][X]复制到dfa[][j](对于匹配失败的情况);
② 将dfa[pat.charAt(j)][j]设为j+1(对于匹配成功的情况);
③ 更新X。
dfa[pat.charAt(0)][0] = 1;
for(int X = 0,j = 1; j < M; j++){
for(int c = 0; c < R; c++){
dfa[c][j] = dfa[c][X];
}
dfa[pat.charAt(j)][j] = j + 1;
X = dfa[pat.charAt(j)][X];
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)