如何使用树找到最长的公共子串?

Posted

技术标签:

【中文标题】如何使用树找到最长的公共子串?【英文标题】:How to find longest common substring using trees? 【发布时间】:2012-06-15 18:37:15 【问题描述】:

根据 wiki 的最长公共子串问题可以使用后缀树来解决。 来自wiki:

一组字符串的最长公共子串可以通过 为字符串构建一个通用的后缀树,然后找到 具有来自所有字符串的叶节点的最深内部节点 在它下面的子树中

我不明白。 示例:如果我有:ABCDEXABCZ 那么后缀树是(XABCZ 的一些分支由于空格而省略):

最长的公共子字符串是ABC,但不是我看不到wiki的描述在这里有什么帮助。ABC不是最深的内部节点与叶节点。 对理解这是如何工作的有帮助吗?

【问题讨论】:

ABC is not the deepest internal nodes with leaf nodes. 不,但是 ABC 树中任何地方最长的 common 节点字符串。下一个最长的是B-CD-E,每个都有两个节点。 是的 ABC 是最长的公共字符串。但我不明白 wiki 描述实际上如何帮助我以编程方式找到它 您必须阅读另一个 Wiki:en.wikipedia.org/wiki/Generalised_suffix_tree。可能有一些更好(更容易理解)的资源here。另见***.com/questions/969448/… @user384706 - 我认为部分问题在于这不是正确的后缀树。您应该只有一个以根 A-B-C 开头的分支,而 C 将有两个孩子:D-E 和 Z。其余分支类似。你所拥有的基本上只是一个后缀列表,它们都有一个指向它们的根节点。 @twalberg:是的,你是对的。 2 个蓝色分支将是一个。但在这种情况下,我如何以编程方式找到它们?我不清楚 wiki 描述有什么帮助 【参考方案1】:

就像之前所说的,你的树是不正确的。

这是通过我的代码运行“ABCDE$XABCZ”时得到的结果。

Suffix Tree code:

String = ABCDE$XABCZ$
End of word character 1 = $
└── (0)
    ├── (20) $
    ├── (22) ABC
    │   ├── (15) DE$
    │   └── (23) Z$
    ├── (24) BC
    │   ├── (16) DE$
    │   └── (25) Z$
    ├── (26) C
    │   ├── (17) DE$
    │   └── (27) Z$
    ├── (18) DE$
    ├── (19) E$
    ├── (21) XABCZ$
    └── (28) Z$

在(紧凑)后缀树中,您需要从所有字符串中找到具有叶节点的最深内部节点。如果在同一深度有多个节点,则必须比较该节点表示的字符串的长度。即 ABC、BC 和 C 都具有相同的深度,因此您必须比较 ABC、BC 和 C 字符串的长度,看看哪个更长;这显然是ABC。

Suffix Trie code:

└── null
    ├── A
    │   └── B
    │       └── C
    │           ├── D
    │           │   └── (E) ABCDE
    │           └── (Z) ABCZ
    ├── B
    │   └── C
    │       ├── D
    │       │   └── (E) BCDE
    │       └── (Z) BCZ
    ├── C
    │   ├── D
    │   │   └── (E) CDE
    │   └── (Z) CZ
    ├── D
    │   └── (E) DE
    ├── (E) E
    ├── X
    │   └── A
    │       └── B
    │           └── C
    │               └── (Z) XABCZ
    └── (Z) Z

在一个(非紧凑的)后缀树中,从所有字符串中找到最深的内部节点,该节点具有叶节点。

希望对你有帮助。

【讨论】:

这是一个“折叠”的后缀树吗?还有什么数字,例如(20)(24) 等? 是的,这是折叠的,但是折叠意味着合并,例如“DE” 为单个节点。然而,所有后缀树都会将“CDE$”和“CZ$”组合成一个带有“DE$”分支和“Z$”分支​​的“C”节点——但折叠后缀树会处理“DE$”作为一个节点,未折叠的后缀树会将“DE$”视为三个节点,每个字符一个。 @user384706 是的,这是一棵倒塌的树。这些数字只是节点标识符,没有什么要注意的。如果您有兴趣,我还创建了一个后缀树。我将其添加到答案中。【参考方案2】:

您实际上还没有绘制后缀树。如果你做得正确,从根本上你只会拥有每个可能的角色一次。仅当单个字母可以具有多个后续后缀时,树才会分裂。这会在树中强制将公共子字符串放在一起,从而使它们可以被找到。

【讨论】:

我不确定我是否在这里关注你。如果字符串是:ABCDBEF,那么在B 下会有一个子分支,用于BCDBEFBEF,但是对于这个例子,即ABCDE,我们不会为每个可能的后缀都有一个分支吗? 在您给出的示例图中,最多应该有一个标记为“A”的根的孩子。您应该已经合并了这两个节点。 @LouisWasserman:真的吗?为什么?AABCDE 中的前缀。为什么会有一个root的子节点A 后缀树的全部意义在于将匹配的后缀前缀合并到同一个根中。根应该有一个分支到ABC,然后最后一个节点应该有两个孩子,一个X和一个DE @LouisWasserman:好的。我同意。但在这种情况下,即拥有 2 个合并节点,我如何使用 wiki 描述以编程方式找到最长的公共子字符串?我被困在这个

以上是关于如何使用树找到最长的公共子串?的主要内容,如果未能解决你的问题,请参考以下文章

没有动态编程或后缀树的最长公共子串

最长回文子串和后缀特里树

迭代器生成器求最长公共子序列求最长公共子串爬楼梯按之字打印二叉树一个字符串按照k步长分组,再进行反转

最长公共后缀-前缀

最长公共子串(动态规划)

请帮忙///如何计算两个 字符串的最长公共子串