有没有找到重复子字符串的有效方法?这里,重复意味着彼此接近的两个相同子串具有相同的值而没有重叠。例如,源字符串是:
ABCDDEFGHFGH
' d'和' FGH'是重复的。 ' F'在序列中出现两次,但是它们彼此不相近,因此它不会重复。所以我们的算法将返回[' D',' FGH']。我想知道是否存在一个优雅的算法而不是蛮力方法?
答案 0 :(得分:3)
它与Longest repeated substring problem有关,它构建Suffix Tree以提供线性时间和空间复杂度的字符串搜索Θ(n)
答案 1 :(得分:1)
效率不高(后缀树 / 数组对于非常大的字符串更好),但非常短的正则表达式解决方案(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"
。
答案 2 :(得分:1)
如果不使用任何可能会变得非常慢的正则表达式,我想最好使用两个游标一起运行。从下面的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"]
但是如果你cr = cl += ts.length
,那么你应该期望结果为["AB", "AB", "AB"]
。