所有后缀的最长前缀字符串长度

时间:2012-01-05 08:13:59

标签: c++ algorithm data-structures

查找字符串所有后缀的最长前缀字符串的长度。

例如字符串ababaa的后缀为ababaababaaabaabaaaaa 。每个字符串与字符串“ababaa”的相似性分别为6,0,3,0,1,1。因此答案是6 + 0 + 3 + 0 + 1 + 1 = 11.

我写了以下代码

#include <iostream>
#include <string.h>

#include <stdio.h>
#include <time.h>

int main ( int argc, char **argv) {
    size_t T;
    std::cin >> T;
    char input[100000];
    for ( register size_t i = 0; i < T; ++i) {
        std::cin >> input;

        double t = clock();

        size_t len    = strlen(input);
        char *left    = input;
        char *right   = input + len - 1;
        long long sol = 0;
        int end_count = 1;
        while ( left < right ) {
            if ( *right != '\0') {
                if ( *left++ == *right++ ) {
                    sol++;
                    continue;
                }
            }
            end_count++;
            left = input; // reset the left pointer
            right = input + len - end_count; // set right to one left.
        }
        std::cout << sol + len << std::endl;
        printf("time= %.3fs\n", (clock() - t) / (double)(CLOCKS_PER_SEC));
    }
}

工作正常,但是对于100000长并且具有相同字符即aaaaaaaaaa.......a的字符串,需要很长时间,我该如何优化这一字符。

6 个答案:

答案 0 :(得分:3)

您可以使用后缀数组:http://en.wikipedia.org/wiki/Suffix_array

答案 1 :(得分:1)

假设你的ababaa是模式P. 我想你可以使用以下算法:

  1. 为P的所有可能后缀创建后缀自动机。
  2. 使用P作为输入来移动自动机,计算到目前为止遍历的边缘。对于自动机的每个接受状态,将当前边缘计数添加到总和。走自动机,直到你到达输入的末端或没有更多的边缘通过。
  3. 总和是结果。

答案 2 :(得分:1)

使用Z算法来计算所有子串的长度,这些子串的长度也以O(n)为前缀,然后扫描结果数组并将其值求和。

参考:https://www.geeksforgeeks.org/sum-of-similarities-of-string-with-all-of-its-suffixes/

答案 3 :(得分:0)

从我所看到的,你使用普通数组来评估后缀,虽然它可能对某些数据集有效,但对于某些情况,例如你提到的那种情况,它将无效。

您需要实现前缀树Trie之类的数据结构。这些代码并不简单,所以如果你不熟悉它们,我建议你仔细阅读它们。

答案 4 :(得分:0)

我不确定Trie是否会给你带来很大的性能提升......但我肯定会考虑它。

我的另一个想法是尝试压缩你的字符串。我没想过,只是一个疯狂的想法...

如果您有这样的字符串:ababaa将其压缩为:abab2a。然后你必须提出一种技术,你可以使用你的算法与这些字符串。优点是您可以有效地将长字符串100000a相互比较。或者更重要的是:你可以非常快地计算你的总和。

但同样,我没有想到,也许这是一个非常糟糕的主意;)

答案 5 :(得分:0)

这是一个java实现:

        // sprefix
        String s = "abababa";
        Vector<Integer>[] v = new Vector[s.length()];
        int sPrefix = s.length();
        v[0] = new Vector<Integer>();
        v[0].add(new Integer(0));
        for(int j = 1; j < s.length(); j++)
        {
            v[j] = new Vector<Integer>();
            v[j].add(new Integer(0));
            for(int k = 0; k < v[j - 1].size(); k++)
                if(s.charAt(j) == s.charAt(v[j - 1].get(k)))
                {
                    v[j].add(v[j - 1].get(k) + 1);
                    v[j - 1].set(k, 0);
                }
        }

        for(int j = 0; j < v.length; j++)
            for(int k = 0; k < v[j].size(); k++)
                sPrefix += v[j].get(k);

        System.out.println("Result = " + sPrefix);