我在Book Algorithms 4th 中学习KMP算法。我可以理解大部分算法但是在dfa构建过程中已经停留了几天。
以模式ABABAC
为例。如果C
处于不匹配状态(dfa的状态为5),我们应该在文本中右移一个字符。所以我们所知道的模式字符是BABA
。但是,如何在施工期间弄清楚dfa的下一个状态?我没理解下面的文字:
例如,要确定当我们在j = 5时遇到与
ABABAC
不匹配时DFA应该执行的操作,我们会使用DFA来了解完整备份会使我们处于状态3 {{1我们可以将BABA
复制到dfa[][3]
。
“完整备份会让我们处于dfa[][5]
状态3”是什么意思,以及如何在没有指定输入的情况下得出这个结论?我无法理解留给文本的图表。任何人都可以解释它的意思吗?我已经试着自己了解了几天,但仍然无法理解。谢谢!
答案 0 :(得分:4)
当您匹配输入字符串时,只能在匹配模式的前5个字符后进入状态5,并且模式的前5个字符为ABABA
。因此,无论您使用哪个输入字符串,都知道状态5之前的文本是“ABABA”。
因此,如果您在状态5中出现不匹配,则可以备份4个字符并再次尝试匹配。但是既然你知道在状态5之前必须出现什么文本,你实际上并不需要输入文本来弄清楚会发生什么。你可以事先弄清楚当你回到同一个地方时你最终会处于什么状态。
备份4个字符并转到状态0:
0:BABA
A不匹配,所以前进并转到状态0
0:ABA
匹配,所以转到状态1
1:BA
B匹配,转到状态2
2:A
匹配,转到状态3
3:
现在我们回到输入中我们之前看过状态5的位置,但现在我们处于状态3。
当我们在状态5中出现不匹配时,总是会发生这种情况,所以我们只是做一个说明“当我们在状态5中出现不匹配时,转到状态3”的说明。
请注意,大多数KMP实现实际上会在failure_table[5]=3
中创建失败表。您的示例实现正在构建完整的DFA[char][state]
,因此它会将所有从状态3到状态5的转换复制到故障情况。这就是说“当我们在状态5中得到不匹配时,做任何状态3做的事情”,这也是一样的。
在移动之前了解以上所有事项
现在让我们加快计算那些失败状态......
当我们在状态5中出现不匹配时,我们可以使用我们到目前为止的DFA来确定如果我们通过将DFA应用于“BABA”来备份并在下一次可能的匹配时重新扫描输入会发生什么。我们最终处于状态3,所以让状态3称为状态5的“失败状态”。
看起来我们必须处理4个模式字符来计算状态5的故障状态,但是当我们计算状态4的故障状态时,我们已经完成了大部分工作 - 我们应用了DFA为“BAB”并最终进入状态2。
因此,为了找出状态5的失败状态,我们只是从状态4(状态2)的失败状态开始,并处理模式中的下一个字符 - 在状态4之后的“A”输入