如何反转字符串的后缀树(找到它代表的字符串)

时间:2015-03-11 10:27:53

标签: string algorithm data-structures suffix-tree

给定一个(修改/损坏)后缀树,它在每个边缘存储当前子字符串的开头和结尾,但不存储子字符串本身,即后缀树,如下所示: enter image description here

这棵树代表字母表上的字符串“banana”:{a,b,n}。

我正在寻找的算法是找到那种树所代表的字符串,对于上面的例子,我希望算法找到“banana”。 我希望在复杂的O(| string |)中使用| string |是要搜索的字符串的长度。 可以假设:

字母表的大小是常量,每个字符串都从索引1开始。

1 个答案:

答案 0 :(得分:0)

  1. 让我们从一些多项式时间解决方案开始:

    • 让我们将字符串中的所有字符划分为等价类。

    • 我们已经知道:它是一个特殊的$符号。

    • 归纳假设:我们假设我们已经将长度为k的后缀的所有字符正确地划分为等价类。我们也可以正确地使用长度为k + 1的后缀。

    • 证明:让迭代遍历长度为i <- 1...k的所有长度,并检查长度为k的后缀和长度为i的后缀的最长公共前缀的长度是否为不是零。如果相应叶子的最低共同祖先不是树的根,则它不为零。如果我们找到了这样的后缀,我们知道它的第一个字母等于当前后缀的第一个字母。因此,我们可以将长度为k + 1的后缀的第一个字母添加到适当的等价类中。否则,它属于自己的等价类。

    • 当所有字符被分成等价类时,我们只需要为每个类分配一个唯一的符号(如果我们需要保持正确的字典顺序,我们可以检查它们中的哪一个更早。要做到这一点。 ,我们需要查看从根开始的边的顺序。

    • 时间复杂度为O(n ^ 3)(有n个就足够了,我们为其中的每一个迭代O(n)其他足够的内容,我们在O(n)中计算其lca (我假设我们在这里使用了一个天真的算法))。到目前为止,非常好。

  2. 现在让我们使用几个观察来获得线性解决方案:

    • 我们真的不需要lca。我们只需要检查它不是根。因此,我们可以将所有叶子划分为基于其祖先的等价类,该祖先是根的直接子。它可以使用深度优先搜索在线性时间内完成。如果它们在同一个类中,则两个足够的最长公共前缀是非空的。

    • 我们实际上并不需要检查所有较短的时间。我们只需要在深度优先搜索顺序中检查最靠近左侧和右侧的一个。从给定的左侧和右侧找到最接近的较小数字是一个标准问题,它有一个带有堆栈的线性解决方案。

    • 就是这样:我们最多检查给定的两个其他两个,每个检查都是O(1)。我们现在有一个线性解决方案。

  3. 此解决方案使用这样的字符串确实存在的假设。如果这个假设不可行,我们可以使用这个算法构造一些​​字符串,然后使用Ukkonnen算法构建一个线性的后缀树,并检查它与给定的完全相同。