string - 找出是否存在两个相邻的相同子串

标签 string algorithm hash substring

我们有一个字符串。

宝 Paypal 贝

现在我们必须检查是否存在一个子字符串,其后跟另一个与第一个子字符串完全相同的子字符串。

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

在这个例子中:

AAB

它会是简单的 A,因为 A 后面跟着另一个 A。

在这个例子中:
ABCDEFGHIJKLMNO
不存在这样的子字符串,所以答案是否定的。


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

有没有人有更好的主意?

最佳答案

我猜您想要遵循此模式的最长子字符串。

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

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

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

0 ≤ Nn - 2

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

  1. Si 为与i 相关的子串,k = 0 且curnode =
  2. 虽然 k < 长度(Si)
    1. 如果从 ii 的 child 的 key 等于 Si[k],然后k = k+1
    2. 否则打破循环。
  3. 如果 k == length(Si),则子串匹配。否则,您继续下一个子字符串。

复杂性总结​​

n 为查询字符串的长度。

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

因此,最坏情况下的总体复杂度是以上各项的总和,并且是 O(n².log(n))

注意事项

我做了上面的算法...因此它不是最优的,如果你足够勇敢,你可以通过this paper描述了一个线性时间算法!无论如何,后缀树是解决这个问题的关键,所以我建议您彻底研究它们。

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

[2]:实际上,最坏情况的复杂度比这个非常朴素的上限要好,但我不知道如何证明它(还?!)。例如,如果有 n - 2 个内部节点,则意味着原始字符串由 n 个相同字符组成。在这种情况下,我们检查的第一个子字符串是匹配项 => 它是 O(n.log(n))。

[3]:如果我们用常规排序替换堆构造 (O(n.log(n))),最后的比较步骤在 < em>O(n²) 而不是 O(n².log(n)) ... 降低 O(n.log(n))(由于排序步骤)和 O(n²)

关于string - 找出是否存在两个相邻的相同子串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28188296/

相关文章:

java - Flappy Bird 遗传算法种群改进

java - Java 中 MD5 的哈希值?

string - Swift 字符串不会转义双引号

algorithm - 从 GPS 坐标记录计算圈数

java - 如何重新分配 StringBuffer 的值?

c++ - 浮点除法的软件实现,舍入问题

Ruby:从哈希 A 到哈希 B 的最快路径

python - 询问 "is hashable"有关 Python 值的信息

string - 如何将字符串元胞数组转换为字符串矩阵?

java - ArrayList<对象> 到 ArrayList<字符串>