关于Java:查找长度为n的重复子串

Find repeating substring of Length N

我必须制作一个Java程序,它找到给定字符串中所有长度为n的子字符串。输入字符串非常长,而暴力方法需要花费太多时间。

我试过:目前,我将分别查找每个子字符串,并使用kmp算法检查该子字符串的重复。这也花费了太多时间。

对于这个问题,什么方法更有效?


1)应该使用后缀树数据结构。

后缀树

这个数据结构可以在O(n*log n)时间内构建(我认为即使在O(N)时间内,使用Ukkonen算法)其中n是输入字符串的大小/长度。这样就可以解决许多(否则)困难的问题。o(m)时间内的任务,其中m是模式的大小/长度。

所以即使我没试过你的问题,我也很确定如果使用后缀树和问题的智能公式,则使用后缀树(在合理的时间内)可以解决问题。

2)关于这些(和相关)主题的一本非常好的书是:

字符串、树和序列的算法

不过,除非你在算法方面受过良好的训练,否则阅读起来并不容易。但好吧,阅读这些东西是获得良好训练的唯一途径;)

3)我建议您也快速了解一下这个算法。

AHO Corasick算法

虽然,我不确定,但是…这个可能有点与你的特定问题无关的话题。


我将采纳@peter.petrov的建议,并通过解释人们如何实际使用后缀树来解决这个问题来加强它:

1
2
3
4
5
 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|)O(|S|)O(|S|log|S|)