这是我用于类似问题的方法:
<?php
$input="AACABABCABCABCP";
//Prepare index array (A..Z) - adapt to your character range
$idx=array();
for ($i="A"; strlen($i)==1; $i++) $idx[$i]=array();
//Prepare hits array
$hits=array();
//Loop
$len=strlen($input);
for ($i=0;$i<$len;$i++) {
//Current character
$current=$input[$i];
//Cycle past occurrences of character
foreach ($idx[$current] as $offset) {
//Check if substring from past occurrence to now matches oncoming
$matchlen=$i-$offset;
$match=substr($input,$offset,$matchlen);
if ($match==substr($input,$i,$matchlen)) {
//match found - store it
if (isset($hits[$match])) $hits[$match][]=$i;
else $hits[$match]=array($offset,$i);
}
}
//Store current character in index
$idx[$current][]=$i;
}
print_r($hits);
?>
我怀疑它是 O(N*N/M) 时间,N 是字符串长度,M 是字符范围的宽度。
它输出我认为您的示例的正确答案。
编辑:
该算法具有在运行时保持有效分数的优势,因此它可用于流,只要您可以通过一些缓冲提前查看。它以效率为代价。
编辑2:
如果允许重复检测的最大长度,这将减少空间和时间的使用:通过if ($matchlen>MAX_MATCH_LEN) ...
限制索引大小和字符串比较长度之类的东西来排除太“早”的过去事件