Algorithm DFA运行时间不是O(n),而是O(nm)

Algorithm DFA运行时间不是O(n),而是O(nm),algorithm,big-o,dfa,nfa,Algorithm,Big O,Dfa,Nfa,如果您有一个包含m个节点的DFA,并且您在一个包含n个字符的字符串上运行它,那么在每个步骤中,您不仅要测试从上一步骤继承的状态,还要再次测试DFA的第一个状态。所以在字符串中的m个字符之后(假设ml进行匹配意味着您将遇到最坏的情况,即在字符串中的l个字符之后有(m-1)个活动状态 我错过了什么?或者,文献中提到的实际实现仅仅关注于知道给定的完整字符串(即不是其中一个子字符串)是否匹配正则表达式的理论问题 从我的立场来看,运行NFA或DFA需要O(nm)次(m是NFA或DFA中的节点数,n个字符数

如果您有一个包含m个节点的DFA,并且您在一个包含n个字符的字符串上运行它,那么在每个步骤中,您不仅要测试从上一步骤继承的状态,还要再次测试DFA的第一个状态。所以在字符串中的m个字符之后(假设m

一个例子,考虑{L} B正则表达式(所有单词从重复的L次开始,跟随B),其DFA具有m=L+1个节点。将它与字符串a{k}b和k>l进行匹配意味着您将遇到最坏的情况,即在字符串中的l个字符之后有(m-1)个活动状态

我错过了什么?或者,文献中提到的实际实现仅仅关注于知道给定的完整字符串(即不是其中一个子字符串)是否匹配正则表达式的理论问题


从我的立场来看,运行NFA或DFA需要O(nm)次(m是NFA或DFA中的节点数,n个字符数)。唯一的问题是NFA比DFA有更多的节点。

历史上,DFA首先被定义为匹配整个字符串,而不是搜索子字符串,这就是为什么文献通常讨论DFA的时间复杂性,即接收单个字符串,然后返回整个字符串是否匹配。如果您有一个匹配整个字符串的DFA,并且希望使用它来搜索子字符串,那么实际上您要多次运行DFA,每个可能的开始位置一次,这就是为什么您要将O(mn)作为运行时而不是O(n)


然而,如果您的目标是匹配某个子字符串,那么重新设计DFA可能会更好。例如,假设您希望使用DFA匹配某个正则表达式R。与其为R构建DFA并从每个可能的位置开始运行,不如为regex∑*R∑*构建DFA。现在,如果输入的任何子字符串与R匹配,则整个字符串与∑*R∑*,因此您只需要在字符串上运行一次DFA。这将运行时降到O(n),因为您只运行一个过程。

历史上,DFA首先定义为匹配整个字符串,而不是搜索子字符串,这就是为什么文献通常讨论DFA的时间复杂性,即接收单个字符串,然后返回整个字符串是否匹配。如果您有一个匹配整个字符串的DFA,并且希望使用它来搜索子字符串,那么实际上您要多次运行DFA,每个可能的开始位置一次,这就是为什么您要将O(mn)作为运行时而不是O(n)


然而,如果您的目标是匹配某个子字符串,那么重新设计DFA可能会更好。例如,假设您希望使用DFA匹配某个正则表达式R。与其为R构建DFA并从每个可能的位置开始运行,不如为regex∑*R∑*构建DFA。现在,如果输入的任何子字符串与R匹配,则整个字符串与∑*R∑*,因此您只需要在字符串上运行一次DFA。这会将运行时降到O(n),因为您只运行一个过程。

如果您确实有DFA,则不会有多个活动状态。DFA定义为只有一个活动状态。每一个字符只能精确地指向下一个状态

如果使用此属性,则从开始状态开始并使用n个字符。在检查的每个字符处: -如果没有转换到非错误状态=>不匹配 -如果存在到非错误状态的转换=>继续

最后检查当前状态是否为最终状态。如果是,则=>成功,否则=>不匹配

在我看来,NFA取O(n*m),DFA取O(n)。DFA性能不依赖于模式复杂性(节点数)


但是我不知道为什么你接受了一个答案,这个答案是使用DFA进行字符串搜索(实际上不是O(n)),而不是使用DFA进行字符串匹配。但如果这是您的问题:有些算法是从DFA派生的,比搜索∑R∑做得更好,这将是Knuth Morris Pratt(针对单一模式)和Aho Corasick(针对多模式)。底层DFA是压缩的,但这两种算法都有一个共同的特性,即它们在任何时候都只对一个没有多个状态的字符执行一次转换(如在NFA中)。

如果确实有DFA,则不会有多个活动状态。DFA定义为只有一个活动状态。每一个字符只能精确地指向下一个状态

如果使用此属性,则从开始状态开始并使用n个字符。在检查的每个字符处: -如果没有转换到非错误状态=>不匹配 -如果存在到非错误状态的转换=>继续

最后检查当前状态是否为最终状态。如果是,则=>成功,否则=>不匹配

在我看来,NFA取O(n*m),DFA取O(n)。DFA性能不依赖于模式复杂性(节点数)


但是我不知道为什么你接受了一个答案,这个答案是使用DFA进行字符串搜索(实际上不是O(n)),而不是使用DFA进行字符串匹配。但如果这是您的问题:有些算法是从DFA派生的,比搜索∑R∑做得更好,这将是Knuth Morris Pratt(针对单一模式)和Aho Corasick(针对多模式)。底层DFA是压缩的,但这两种算法都有一个共同的特性,即它们对一个字符在任何时候都不具有多个状态(如NFA中)只执行一次转换。

我在正则表达式的上下文中研究了这一点,我没有想到向DFA添加∑*以便它可以找到子字符串匹配。这样做会得到O(n),我天真地想必须重新测试fir