重复的子字符串搜索

时间:2016-12-22 11:25:38

标签: algorithm search substring

有没有找到重复子字符串的有效方法?这里,重复意味着彼此接近的两个相同子串具有相同的值而没有重叠。例如,源字符串是:

ABCDDEFGHFGH

' d'和' FGH'是重复的。 ' F'在序列中出现两次,但是它们彼此不相近,因此它不会重复。所以我们的算法将返回[' D',' FGH']。我想知道是否存在一个优雅的算法而不是蛮力方法?

3 个答案:

答案 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"]