对于以下问题,我很难找到比O(n ^ 2)更好的方法。
我收到一个字符串,例如xyxxz
。
现在我需要在给定字符串的每个前缀中找到匹配字符的总数。
这里,string的可能前缀是:
xyxxz : matching characters is 5
yxxz : matching characters is 0 (since 1st character doesnt match)
xxz : matching characters is 1
xz : matching characters is 1
z : matching characters is 0
这应该是输出。 我做了以下代码:
cin>>str;
len=str.length();
for(i=0;i<len;i++){
sum=0;
k=i;
for(int j=0;j<len;j++)
{
if(str[k] == str[j]){
sum++;
k++;
}
else
break;
}
cout<<sum<<" "; //I get the output 5 0 1 1 0
}
但是它是O(n ^ 2)。我想要一个更好的方法:可能是O(n)或O(nlogn)。
提前致谢。
答案 0 :(得分:2)
这可以使用以下程序在线性时间内完成:
构造后缀数组SA以及LCP数组(最长公共前缀数组)。后缀数组是字符串所有后缀的按字典顺序排序的列表(类似于您在示例中给出的列表,但按字典顺序排序。请注意,每个后缀由其在原始字符串中的起始位置表示,即每个后缀一个整数) 。 LCP也是一个整数数组,长度与后缀数组相同。在每个位置i> 0,LCP [i]是后缀阵列的第i个后缀与第(i-1)个后缀共同的最长前缀;我们设置了LCP [0]:= 0。
后缀数组可以使用Skew算法(也称为DC算法)以线性时间构造,并且可以在O(n)时间内在后缀数组旁边构造LCP阵列。有关进一步的想法和实施,请参阅SO post on state-of-the-art suffix array algorithms。
识别后缀数组中完整字符串的位置(例如,通过线性扫描后缀数组以查找包含整数0的条目)。
从该位置开始沿着LCP阵列向左和向右走,以识别每个后缀与完整字符串共有的最长前缀。我在this older SO post。
备注虽然这需要不超过O(n)的内存和时间,因此理论上是最佳的,但这是一个非常复杂的过程,只有在你的字符串非常长时才会在实践中有用。
答案 1 :(得分:1)
如果为字符串构建后缀树,则可以遍历后缀树以查找匹配的长度。根节点中与第一个字符不匹配的任何子节点的值都为零,其所有后代也将如此。然后,根节点的子节点的所有子节点都具有匹配,并且至少具有与该边缘的匹配长度相等的匹配。
答案 2 :(得分:1)
使用后缀数组。后缀数组DC3将在O(N)时间内完成,其中N是原始字符串中的字符数。
答案 3 :(得分:0)
int strcoll (register const char *s1, register const char *s2)
{
while (*s1 == *s2++) {
if (*s1++ == '\0') {
return 0;
}
}
return *s1 - *--s2;
}
此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续使用以下对,直到字符不同或直到出现空字符信号表示字符串结束为止。
返回一个表示字符串之间关系的整数值: 零值表示两个字符串相等。 大于零的值表示不匹配的第一个字符在str1中的值大于在str2中的值;小于零的值表示相反。
答案 4 :(得分:0)
我不擅长计算O值..但这是你需要的另一个实现。我认为它更有效率。
cin >> str;
len=str.length();
for(i=0;i<len;i++)
{
sum=0;
k=0;
while(str[k + sum] == str[i + sum])
{
sum++;
}
cout << sum ;
}