重复子串搜索
Posted
技术标签:
【中文标题】重复子串搜索【英文标题】:Duplicate substring searching 【发布时间】:2017-05-08 00:23:10 【问题描述】:有没有找到重复子串的有效方法?在这里,重复意味着两个彼此靠近的相同子字符串具有相同的值而没有重叠。例如,源字符串是:
ABCDDEFGHFGH
“D”和“FGH”重复。 'F' 在序列中出现了两次,但是它们彼此并不接近,因此不会重复。所以我们的算法将返回 ['D', 'FGH']。我想知道是否存在一种优雅的算法而不是蛮力方法?
【问题讨论】:
你能解释一下'duplicate'是什么意思吗,在你的例子中'duplicate'是在第一个之后返回自己的子字符串,但重复意味着在任何地方返回自己的子字符串,例如在您的情况下,字母 F 也是重复的..所以请尽量具体,以便我们为您提供帮助 @Oriel.F 很抱歉造成混乱。现在清楚了吗?AAAA
的正确答案是什么?可能是['A', 'AA']
作为一个集合,但我们是否需要考虑重复出现三次的A
?
继续加萨的问题,答案是什么:ABABABAB,是 'AB','ABAB' 还是只是 ABAB?我的意思是我们是否考虑较长字符串的子字符串?
【参考方案1】:
它与Longest repeated substring problem有关,它构建Suffix Tree以提供线性时间和空间复杂度的字符串搜索Θ(n)
【讨论】:
感谢您的回答。很抱歉没有把问题说清楚。要求两个子串彼此靠近且不重叠。这个算法可以扩展来满足需求吗? @maple:是的;作为第一次尝试,我建议使用 suffix array,它更容易构造,但具有O(n*log(n))
时间复杂度(即比后缀树稍慢)。【参考方案2】:
效率不高(后缀树/数组更适合非常大的字符串),但是非常短的正则表达式解决方案(C#):
string source = @"ABCDDEFGHFGH";
string[] result = Regex
.Matches(source, @"(.+)\1")
.OfType<Match>()
.Select(match => match.Groups[1].Value)
.ToArray();
解释
(.+) - group of any (at least 1) characters
\1 - the same group (group #1) repeated
测试
Console.Write(string.Join(", ", result));
结果
D, FGH
如果有歧义,例如"AAAA"
我们可以提供"AA"
以及"A"
解决方案执行贪婪,因此返回"AA"
。
【讨论】:
【参考方案3】:不使用任何可能会很慢的正则表达式,我想最好使用两个游标并排运行。从下面的 JS 代码中可以很明显地看出算法。
function getNborDupes(s)
var cl = 0, // cursor left
cr = 0, // cursor right
ts = "", // test string
res = []; // result array
while (cl < s.length)
cr = cl;
while (++cr < s.length)
ts = s.slice(cl,cr); // ts starting from cl to cr (char @ cr excluded)
// check ts with subst from cr to cr + ts.length (char @ cr + ts.length excluded)
// if they match push it to result advance cursors to cl + ts.length and continue
ts === s.substr(cr,ts.length) && (res.push(ts), cl = cr += ts.length);
cl++;
return res;
var str = "ABCDDEFGHFGH";
console.log(getNborDupes(str));
在整个过程中ts
将采用以下值。
A
AB
ABC
ABCD
ABCDD
ABCDDE
ABCDDEF
ABCDDEFG
ABCDDEFGH
ABCDDEFGHF
ABCDDEFGHFG
B
BC
BCD
BCDD
BCDDE
BCDDEF
BCDDEFG
BCDDEFGH
BCDDEFGHF
BCDDEFGHFG
C
CD
CDD
CDDE
CDDEF
CDDEFG
CDDEFGH
CDDEFGHF
CDDEFGHFG
D
E
EF
EFG
EFGH
EFGHF
EFGHFG
F
FG
FGH
虽然cl = cr += ts.length
部分决定是否从匹配的子字符串之前或之后重新开始搜索。截至目前上述代码; "ABABABAB"
输入将返回 ["AB","AB"]
for 但如果您将其设为 cr = cl += ts.length
那么您应该期望结果为 ["AB", "AB", "AB"]
。
【讨论】:
感谢您的回答。这是鼓舞人心的,虽然代码可能不正确。我试过“1ABC2ABC33”,输出只有['3']。看起来“cr”的功能超载了。它不能同时是“end-of-test-string”和“cursor-of-sub-string”。恕我直言,该过程需要 3 个嵌套循环。 @Morgan Cheng 这个算法找到了相邻的骗子,所以它只返回3个是正常的。以上是关于重复子串搜索的主要内容,如果未能解决你的问题,请参考以下文章