我必须创建一个Java程序,它在给定的String中查找长度为n的所有重复子字符串。输入字符串非常长,蛮力方法需要花费太多时间。
我已经尝试过了:
现在我分别找到每个子字符串,并使用KMP alogrithm检查该子字符串的重复。这也花了太多时间。
针对此问题的更有效方法是什么?
答案 0 :(得分:3)
1)您应该考虑使用后缀树数据结构。
该数据结构可以在O(N * log N)时间内建立
(我认为即使在O(N)时间使用Ukkonen算法)
其中N是输入字符串的大小/长度
然后它允许解决许多(否则)困难的
O(M)时间中的任务,其中M是模式的大小/长度。
所以即使我没有尝试你的特定问题,我也很确定 如果你使用后缀树和你的问题的智能公式,那么 问题可以通过使用后缀树(合理的O时间)来解决。
2)关于这些(及相关)科目的一本非常好的书就是这本书:
Algorithms on Strings, Trees and Sequences
除非你在算法方面训练有素,否则它并不容易阅读 但是好的,阅读这些东西是获得良好训练的唯一途径;)
3)我建议您快速浏览一下这个算法。
尽管如此,我不确定但是......这个可能有点啰 关于你的特定问题的偏离主题。
答案 1 :(得分:2)
我将采用@ peter.petrov的建议并通过解释如何实际使用后缀树来解决问题来增强它:
1. Create a suffix tree from the string, let it be `T`.
2. Find all nodes of depth `n` in the tree, let that set of nodes be `S`. This can be done using DFS, for example.
3. For each node `n` in `S`, do the following:
3.1. Do a DFS, and count the number of terminals `n` leads to. Let this number be `count`
3.2. If `count>1`, yield the substring that is related to `n` (the path from root to `n`), and `count`
请注意,此算法会处理长度为n
的任何子字符串,并将其添加到集S
,并从那里通过计算终端数来搜索这实际上是子字符串的次数子串导致。
这意味着问题的复杂性为O(Creation + Traversal)
- 意思是,您首先创建树然后遍历它(很容易看到您不会在步骤2-3中遍历每个节点树不止一次)。由于遍历显然更快"而不是树的创建 - 它会留下O(Creation)
,正如@ perer.petrov指出的那样O(|S|)
或O(|S|log|S|)
取决于您选择的算法。