我之前问了同样的问题,但没有得到我想要的。所以必须再次发布。
我有一个很长的字符串,里面没有任何空格。现在我试图在这个长字符串中搜索重复的子字符串(任何类型,没有特定的模式)。重复的长度可以是(min,max)之间的范围,即(min = 3.max = 5)。
例如: String s =“atggucttuaccccggucttaacccc”; 其中“gguctt”和“acccc”是两个不同的重复子串(我在运行代码之前不知道这一点)。
所以我在C#中徘徊,有没有快速的方法来确定重复和重复发生的位置?
提前致谢。
答案 0 :(得分:2)
您实际上是在寻找字符串中的子字符串,但子字符串由字符串中每个可能的子字符串组成。
我将首先迭代块长度,从2(或任何最小匹配应该是),到字符串长度的一半(长度超过字符串长度的一半的字符串不能重复)。
对于每个块大小,我将遍历字符串,使用适当大小的块并使用字符串匹配算法(如Boyer-Moore(或内置字符串搜索算法))来查看字符串是否重复。请注意,只需要搜索字符串的其余部分,如果字符串中有较早的重复,那么它将与该块的区域匹配。您还可以限制搜索区域以消除字符串中的最后一个(chunk_size - 1)字符,因为匹配不可能在那之后开始(尽管您的字符串搜索算法可能会为您执行此操作)。我还会维护所有已经检查过的块的哈希表,以避免再次检查它们,这对于块大小很小的前几次迭代尤其重要。
在伪代码中:
match_min = 2
match_max = 5
search_cache = Hashtable()
for (chunk_size = match_min; chunk_size < min(match_max+1, len(str)/2); chunk_size++){
for (start = 0; start < len(str) - chunk_size; start++){
sub = str.substring(start, start + chunk_size)
// We want to know if sub repeats
if (sub not in search_cache)
search_cache[sub] = str.substring(start + chunk_size, len(str) - chunk_size + 1).find(sub)
if (search_cache[sub] != -1)
print "MATCH FOUND %s at %d-%d" % (sub, start, search_cache[sub])
}
}
这只会为每个块找到一个匹配(并且一些块看起来会匹配自己),但可以很容易地修改以找到所有匹配(只需使find函数返回所有匹配,并修改print语句的工作方式)
这个效率大致为O(c * m * n),其中c是表示字符串搜索算法效率的常量(进行字符串搜索的分摊成本),m是字符串的大小,和n是(最大 - 最小)。它也是字符串中重复量的函数,就像熵低一样,search_cache会为您节省更多时间。将c近似为O(n)使函数大致为O(n ^ 2)。
答案 1 :(得分:1)
如果字符串很长,您可能需要查看Suffixtrees或后缀。他们有效地解决了这个问题和类似的问题。
答案 2 :(得分:0)
试试这个:
var matches = Regex.Matches("atggucttuaccccggucttaacccc", @"((.)\2+)")
它也会给你比赛的位置。更多信息here。
编辑:刚刚意识到你需要任意重复的字符串匹配,而不仅仅是重复的字符匹配。