找出是否存在两个相同的子串,一个接一个

时间:2015-01-28 09:07:51

标签: string algorithm hash substring

我们有一个字符串。

ABAEABABEABE

现在我们必须检查是否存在一个子字符串,接下来是另一个子字符串,它与第一个子字符串完全相同。

在这个例子中: ABAEAB的 ABE ABE
ABE之后是ABE,这是两个相同的子串。

在这个例子中:

AAB

它只是A,因为A后面是另一个A.

在这个例子中:
ABCDEFGHIJKLMNO
没有这样的子串,所以答案是否。


我只设法找到一个运行在O(n ^ 2)的算法。这是哈希及其前缀。然后,对于每个字母,我们简单地展开并检查以该字母结尾的所有单词。有n个字母。我们需要扩展它n次。所以它是O(n ^ 2)。我相信应该有一个针对这个问题的O(n log n)算法。

有没有人有更好的主意?

2 个答案:

答案 0 :(得分:2)

我想你想要这个模式之后可能的最长子串。

要做的第一件事是构建输入字符串的后缀树。使用Ukkonen's algorithm,这是 O(n)

现在,您提供的条件如何在后缀树中翻译?首先,您正在寻找重复子串 [1] 重复的子字符串将显示为后缀树的内部节点。从 n -char字符串构建的后缀树中的The maximum number of nodes 2n - 1

您可以使用它们的长度(字符数)构建包含此类重复子字符串的Max-Heap。 NOT 保持长度优于 N / 2 的子串(参见[1])。这是 O(N),其中 N 是后缀树的内部节点数。对于任何后缀树:

  

0≤ N n - 2

现在,您从优先级队列中取出最大值并处理您获得的内部节点 i

  1. S i 成为与 i k = 0和 curnode <相关的子字符串/ em> = i
  2. k &lt;长度(取值<子> I 的)
    1. 如果从 i i 的子项的键等于 S i [k] ,然后 k = k + 1
    2. 否则打破循环。
  3. 如果 k == length( S i ),则子字符串是匹配的。否则,你继续下一个子串。
  4. 复杂性摘要

    n 为查询字符串的长度。

    • 构建后缀树: O(n)
    • 构建重复子串的最大堆: [3]
      • 识别重复的子串(即内部节点)并将其存储在数组中: O(n)
      • 修复数组: O(n)
    • 找到最佳匹配: O(n².log(n)) [2]

    因此,整体最坏情况的复杂性是上述的总和,并且是 O(n².log(n))

    备注

    我制作了上面的算法...因此它不是最理想的,如果你足够勇敢,你可以通过描述线性时间算法的this paper!无论如何,后缀树是这个问题的关键,所以我建议你仔细研究它们。

    [1] :警告,重复的子串可能会部分重叠!

    [2] :实际上,最糟糕的情况复杂性比这个非常天真的上限要好,但我不知道如何证明它(还有?!)。例如,如果有 n - 2 内部节点,则意味着原始字符串由 n 出现的相同字符组成。在这种情况下,我们检查的第一个子字符串是match =&gt;它是O(n.log(n))。

    [3] :如果我们通过常规排序( O(n.log(n))替换堆构造,最后的比较步骤将在< em> O(n²)而不是 O(n².log(n)) ...降低 O(n.log(n))之间的总体复杂度< / em>(由于排序步骤)和 O(n²)

答案 1 :(得分:0)

这个问题可以通过“分而治之”的Main-Lorentz算法来解决:
Michael Main,Richard J. Lorentz。用于查找字符串中所有重复的O(n log n)算法[1982]

修改algorithm description and C++ implementation in Russian(可能会使用Chrome浏览器进行翻译)

还存在linear-time algorithm(不了解实际实施)