Knuth-Morris-Pratt 算法中的 DFA 构造

Posted

技术标签:

【中文标题】Knuth-Morris-Pratt 算法中的 DFA 构造【英文标题】:DFA construction in Knuth-Morris-Pratt algorithm 【发布时间】:2015-08-13 10:01:15 【问题描述】:

我指的是 Sedgewick 的“算法”一书中(第 4 版)中用于子串搜索的 Knuth-Morris-Pratt (KMP) 算法的大纲。

KMP 算法在基于确定性有限自动机 (DFA) 的子字符串搜索中使用备份。我了解 DFA 是如何进入算法的,但是我不了解如何构造 DFA,这是通过以下代码 sn-p 完成的:

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];

其中M 是模式pat 的长度,R 是字母表的大小。 charAt()函数返回相应位置字符的整数值。

有人可以解释这段代码以什么方式构建 dfa 吗?我迷失在内部 for 循环的实际直观含义中。

【问题讨论】:

dfa 是一个带有失败链接的状态表。看到这个问题:***.com/questions/23260938/… 【参考方案1】:

让我们看一下模式 ACACAGA 的以下 FA。

上图表示模式 ACACAGA 的图形和表格表示。

这里,DFA 中的状态数是 M + 1,其中 M 是模式的长度。构造 DFA 的主要内容是从当前状态中为每个可能的字符获取下一个状态。给定一个字符 x 和一个状态 k,我们可以通过考虑字符串“pat[0..k-1]x”来获得下一个状态,它基本上是模式字符 pat[0]、pat1 ... pat[ k-1] 和字符 x。这个想法是获取给定模式的最长前缀的长度,使得前缀也是“pat[0..k-1]x”的后缀(LPS)。长度的值给了我们下一个状态。

例如,让我们看看如何从当前状态 5 和上图中的字符“C”获取下一个状态。我们需要考虑字符串“pat[0..5]C”,即“ACACAC”。前缀为“ACACAC”后缀的模式的最长前缀长度为4(“ACAC”)。所以下一个状态(从状态 5 开始)是字符“C”的 4。

// dfa[i][j] = k denotes the transition function will go k'th state 
// with character i from state j

// DFA will go always (i + 1)'th state from i'th state 
//if the character c is equal to current character of pattern 
dfa[pat.charAt(0)][0] = 1;

//  here X is initialized with LPS (longest prefix suffix) 
// of pattern[0....j - 1]. LPS[0] is always 0
for (int X = 0; j = 1; j< M; j++) 
    for (int c = 0; c < R; c++)  // for all possible characters
        // transition function from j'th state taking character c 
        // will go to the same state where it went from X(LPS)'th state
        // taking character c (justify it with an example) 
        dfa[c][j] = dfa[c][X];
    
    // DFA will go always (i + 1)th state from i'th state if 
    // the character c is equal to current character of pattern
    dfa[pat.charAt(j)][j] = j + 1;
    X = dfa[pat.charAt(j)][X]; // update LPS

【讨论】:

有人能帮我把它移植到python吗? pat.charAt(j) 返回一个错误,因为它是一个字符串。我使用ord() 转换为Unicode 以避免错误:self.dfa[ord(self.pat[0])][0] = 1 但算法没有返回正确的答案。斌:pastebin.com/NyCpfcUK X[1..j-1] 间隔的 LPS,而不是 [0..j-1] 间隔。

以上是关于Knuth-Morris-Pratt 算法中的 DFA 构造的主要内容,如果未能解决你的问题,请参考以下文章

除了 Knuth-Morris-Pratt、Rabin-Karp 等,还都有哪些可用的字符串匹配算法?

字符串匹配算法:KMP(The Knuth-Morris-Pratt Algorithm)

ZOJ 3957 Knuth-Morris-Pratt Algorithm

KMP算法介绍

压力kmp是啥意思

php Algoritma Knuth-Morris-Pratt