字符串中的子字符串计算

时间:2012-07-26 04:19:51

标签: c++ string algorithm suffix-array

对于以下问题,我很难找到比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)。

提前致谢。

5 个答案:

答案 0 :(得分:2)

这可以使用以下程序在线性时间内完成:

  1. 构造后缀数组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

  2. 识别后缀数组中完整字符串的位置(例如,通过线性扫描后缀数组以查找包含整数0的条目)。

  3. 从该位置开始沿着LCP阵列向左和向右走,以识别每个后缀与完整字符串共有的最长前缀。我在this older SO post

  4. 中详细介绍了此过程

    备注虽然这需要不超过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 ;

}
相关问题