【问题标题】:string matching with finite automata字符串匹配有限自动机
【发布时间】:2012-01-06 11:55:03
【问题描述】:

我正在阅读 Cormen 的“算法简介”一书中的字符串算法。对于如下所示的过渡。

我的问题:我们为什么要做min(m+1, q+2) 以及为什么我们要将 m 增加 1 和 q 增加 2。

以下链接具有上述问题的背景。

http://people.scs.carleton.ca/~maheshwa/courses/5703COMP/Fall2009/StringMatching.pdf

请在这里举一个简单的例子。

Algorithm Compute-Transition-Function(P, Sigma)
m = length(P);
for  q = 0 through m  do
   for each character  x  in Sigma
       k = min(m+1, q+2);
       repeat  k = k-1  // work backwards from q+1
       until  Pk 'is-suffix-of' Pqx;
       d(q, x) = k; // assign transition table
   end for;
end for;

return  d;
End algorithm.

【问题讨论】:

  • 您需要添加更多上下文才能使这个问题对任何人有用。
  • 你的意思是这本书吗:Introduction to algorithms?
  • 是的,这本书是 Cormen 等人的算法导论
  • 请在问题中加入上下文,而不是作为另一个页面的链接。

标签: string algorithm


【解决方案1】:
  • 它是m + 1,因为在下一个repeat 循环中k 首先减少。
  • 它是q + 2,因为在repeat 中你以q + 1 开头,所以至少有1 个字符。

以下代码可能存在边界问题(缺少 q == m), 但想让索引更清晰一点。

m = length(P);
for  q = 0 through m - 1 do // Loop through substrings [0, q+1]
   for each character  x  in Sigma
       k = q+1;
       // work backwards from q+1
       while not Pk 'is-suffix-of' Pqx;
       do k = k-1; end do;
       d(q, x) = k; // assign transition table
   end for;
end for;

return  d;

【讨论】:

  • 能否详细介绍一下q+2。感谢您对 m+1 的帮助。
  • 一个从 q+1 向后工作(如评论)。伪代码有点不雅;我会给出一个经过编辑的版本。
【解决方案2】:

代码已经解释,所以这里是一个例子来看看发生了什么

假设字符串是 nano

所以我们希望我们的状态与模式部分匹配。 "nano" 的可能部分匹配是 "", "n", "na", "nan", or (the complete match) "nano" 本身。换句话说,它们只是字符串的前缀。一般来说,如果模式有m个字符,我们需要m+1个状态;这里 m=4 有五个状态。

如果我们刚刚看到 "...nan" ,又看到另一个角色 "x" ,我们应该进入什么状态?显然,如果 x 是匹配中的下一个字符(此处为“o”),我们应该转到下一个较长的前缀(此处为“nano”)。很明显,一旦我们看到完整的比赛,我们就停留在那个状态。但是假设我们看到一个不同的字符,例如 "a" ?这意味着到目前为止的字符串看起来像 "...nana" 。我们可以进行的最长部分匹配只是 "na" ,即我们可以使用最后 2 个字符。所以从状态 "nan" 开始,我们应该画一个标记为 "a" 的箭头到状态 "na" 。注意"na""nano" 的前缀(所以它是一个状态)和"nana" 的后缀(所以它是与我们刚刚看到的一致的部分匹配)。

一般来说,从状态+字符到状态的转换是最长的字符串,它同时是原始模式的前缀和我们刚刚看到的状态+字符的后缀。这足以告诉我们所有的转换应该是什么。如果我们正在寻找模式 "nano" ,则转换表将是

     n       a       o      other
    ---     ---     ---     ---
empty:  "n"     empty   empty   empty       
"n":    "n"     "na"    empty   empty
"na":   "nan"   empty   empty   empty   
"nan":  "n"     "na"    "nano"  empty    //just as an illustration, nan + n = n because we can only use the last 'n', nan + a = na because now we can use the last two 'na'
"nano": "nano"  "nano"  "nano"  "nano"

那么现在我们如何使用这个表来实际进行模式搜索呢?

在字符串 "banananona" 上对此进行模拟,我们通过一次移动一个字符来获得空、空、"n", "na", "nan", "na", "nan", "nano", "nano", "nano" 的状态序列。由于我们以状态 "nano" 结束,因此该字符串在某处包含 "nano"。因此,让我们扩展一下正在发生的事情以及如何使用上表,在“b”处,我们没有处于任何可能的状态'n', 'na', 'nan', 'nano'。所以它被认为是空的......就像我们到达'ba'时一样。当我们点击下一个字符'n'时,我们基本上是从空到n,所以我们使用上面的表格,看到它以'n'结尾。现在我们得到了香蕉的第 4 个字符,所以我们从'n' 到添加一个……再次使用表格,看到它最终处于状态'na',依此类推……

【讨论】:

  • 感谢您对示例的清晰解释和出色的演练。
【解决方案3】:

如果在使用x之前最长匹配前缀是q字符长,则转换表中的条目d(q,x)包含使用字符x之后模式的最长匹配前缀的长度。由于我们消耗一个字母,它不能大于q+1,而且由于模式的长度为m,它最多也可以是m。内部循环是repeat k = k-1 until condition(k),所以在它测试任何东西之前,k 被递减,因此k 的开始必须比最大可能结果k = min(m,q+1) + 1 大1。如果内部循环是while negated_condition(k) { k = k-1; },则应以k = min(m,q+1) 开头。

请注意,使用 Knuth-Morris-Pratt 算法的边界表可以更有效地计算转换表。

【讨论】:

    猜你喜欢
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多