String 如何在至少重复一次的字符串中找到最大的序列?
正在尝试解决以下问题: 给定任意长度的字符串,查找该字符串中出现多次且没有重叠的最长子字符串 例如,如果输入字符串是String 如何在至少重复一次的字符串中找到最大的序列?,string,algorithm,language-agnostic,String,Algorithm,Language Agnostic,正在尝试解决以下问题: 给定任意长度的字符串,查找该字符串中出现多次且没有重叠的最长子字符串 例如,如果输入字符串是ABCABCAB,则正确的输出将是ABC。您不能说ABCAB,因为在两个子字符串重叠的地方只会发生两次,这是不允许的 对于包含几千个字符的字符串,有什么方法可以合理快速地解决这个问题吗 (在任何人提出问题之前,这不是家庭作业。我正在寻找优化Lindenmayer分形渲染的方法,因为它们往往会花费大量的时间来使用天真的海龟图形系统在高迭代级别上绘制。)首先,我们需要定义子字符串的开始
ABCABCAB
,则正确的输出将是ABC
。您不能说ABCAB
,因为在两个子字符串重叠的地方只会发生两次,这是不允许的
对于包含几千个字符的字符串,有什么方法可以合理快速地解决这个问题吗
(在任何人提出问题之前,这不是家庭作业。我正在寻找优化Lindenmayer分形渲染的方法,因为它们往往会花费大量的时间来使用天真的海龟图形系统在高迭代级别上绘制。)首先,我们需要定义子字符串的开始符号并定义长度。迭代所有可能的起始位置,然后通过二进制搜索计算长度(如果可以找到长度为a的substr,则可以找到长度较长的substr,函数看起来很单调,因此bin搜索应该可以)。然后找到等于N的子串,使用KMP或Rabin-Karp任何线性算法都可以。总N*N*log(N)。这太复杂了吗? 代码类似于:
for(int i=0;i<input.length();++i)
{
int l = i;
int r = input.length();
while(l <= r)
{
int middle = l + ((r - l) >> 1);
Check if string [i;middle] can be found in initial string. Should be done in O(n); You need to check parts of initial string [0,i-1], [middle+1;length()-1];
if (found)
l = middle + 1;
else
r = middle - 1;
}
}
for(int i=0;i 1);
检查是否可以在初始字符串中找到字符串[i;middle]。应在O(n)中完成;您需要检查初始字符串[0,i-1]、[middle+1;length()-1];
如果(找到)
l=中间+1;
其他的
r=中间-1;
}
}
有意义吗?这看起来像是后缀树问题。创建后缀树,然后查找包含多个子项的最大压缩分支(在原始字符串中出现多次)。压缩分支中的字母数应为最大子序列的大小 我在这里发现了类似的东西:
看起来它可以用O(n)来完成。下面是一个长度为11的字符串的示例,您可以对其进行概括
- 将区块长度设置为楼层(11/2)=5
- 以5个字符为单位扫描字符串以查找重复。将有3个比较
- 如果你发现了一个复制品,你就完蛋了。否则,将区块长度减少到4,并重复,直到区块长度变为零
String s
int len = floor(s.length/2)
for int i=len; i>0; i--
for j=0; j<=len-(2*i); j++
for k=j+i; k<=len-i; k++
if s.substr(j,j+i) == s.substr(k,k+i)
return s.substr(j,j+i)
return null
字符串s
内部长度=地板(标准长度/2)
对于int i=len;i> 0;我--
对于j=0;这种分析通常在基因组序列中进行。看看这张纸。它有一个有效的实现(c++),用于解决重复:
可能是您正在寻找的是否将ABC
以某种方式评为比同样长度的BCA
或CAB
更高的级别(词典排序?)?字符串AAA
的答案是什么A
或AA
?@Piotrek:'A',因为没有超过一组的AA
不重叠。@RobotWoods:不按字典顺序排列;我主要是以这个为例。任何长度相等的子字符串都应同样有效。如果你需要一个决胜局,胜利者是出现次数最多的一个。如果你仍然需要一个平局破坏者,那么(这是完全任意的)赢家就是第一次迭代在字符串中出现得最早的人。对不起,但我不知道这意味着什么。为了回答更多的评论,我认为这是一个很好的主意。你最好为那些不理解的人解释一下原因+1我通过链接的帖子点击了上面的描述性文章,找到了“最长重复子串”的以下示例:“issi'(在
missippi'的情况下)”。很遗憾,这违反了无重叠规则。是的,它们没有避免重叠的约束。这就是为什么他们要走从根到叶的整个道路。如果你不想重叠,你应该只使用一个压缩分支,那就是ssi
,我认为这是显而易见的答案。如果你有ABCXABC
?你的解决方案不是假设第二次出现在第一次之后吗?无论如何,你的解决方案是(至少)O(长度^2)
,我很确定这不是最优的;它锚定第一个子字符串,然后开始搜索第一个子字符串后的第一个字符,比较相同大小的块。我不认为一个解决方案比O(n^2)更好。。。但我可能错了。
String s
int len = floor(s.length/2)
for int i=len; i>0; i--
for j=0; j<=len-(2*i); j++
for k=j+i; k<=len-i; k++
if s.substr(j,j+i) == s.substr(k,k+i)
return s.substr(j,j+i)
return null