字符串的不同子字符串数

时间:2019-02-14 07:45:43

标签: c++ algorithm substring trie

我正在求解DISTINCT SUBSTRING(给定一个字符串,我们需要找到其不同子字符串的总数)。
我正在使用后缀trie来解决它。
我正在通过测试用例,但是提交时得到TLE。另外,消耗的空间非常大,为4093M

注意:由于总共可以包含256个字符,因此我将数组大小设置为257, 并以ascii值作为索引。

我现在在想什么:

for(int i=0;i<p;i++){
    string temp = str.substr(i,p-i);
    insert1(root,temp);
}

由于substr()可能会花费O(n)的时间,因此在最坏的情况下,插入函数也会花费 (n)最坏情况下的时间,循环的O(n):O(n ^ 3)。这就是我的头衔。

  

错误:无法将'temp'从'std :: __ cxx11 :: string * {aka std :: __ cxx11 :: basic_string *}'转换为'std :: __ cxx11 :: string {aka std :: __ cxx11 :: basic_string}'| || ===构建失败:2个错误,0个警告(0分钟,0秒)=== |

因此,我正在考虑将substr()替换为以下内容:

for(int i=0;i<p;i++){
     string *temp = &str[i];
     insert1(root,temp);
}  ///and it is giving me error please suggest here what is the mistake and what to do

这样我可以节省O(n)时间。

请告诉我如何修改我的trie方法,使它被接受。

#include<iostream>
#include<string>
using namespace std;

const int alphabetsize = 257;
int cnt=0;
struct trienode{
    struct trienode* children[alphabetsize];
    bool isendofword;
};

struct trienode *getnode(void){
    struct trienode *newnode = new trienode;
    newnode->isendofword = false;
    for(int i=0;i<alphabetsize;i++){
        newnode->children[i]=NULL;
    }
    return newnode;
}
void insert1(struct trienode* root,string &key){
    struct trienode *temp = root;
    for(int i=0;i<key.length();i++){
        int index = key[i];
        if(!temp->children[index]){
            temp->children[index]=getnode();
            cnt++;
        }
        temp = temp->children[index];
    }
    temp->isendofword=true;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cnt=0;
        string str;
        cin>>str;
        int p = str.length();
        struct trienode* root = getnode();
        for(int i=0;i<p;i++){
            string temp = str.substr(i,p-i);
            insert1(root,temp);
        }
        cout<<cnt<<endl;
    }

}

2 个答案:

答案 0 :(得分:1)

我没有C ++经验,但是您评论的错误似乎可能是由于编译器对遇到变量temp时收到的变量类型的不同期望。

正如其他人在SPOJ和注释中所指出的那样,由于输入长度仅为256个字符,因此您可以避免使用蛮力散列并计算所有子字符串出现的次数。

另一种选择是检查后缀数组中字符串的最长公共前缀,这两种前缀都有已知的构造算法。如果我们从后缀数组的末尾进行迭代,则当前后缀长度与最长的公共前缀及其右边的邻居之间的差会告诉我们引入了多少个新的不同子字符串。

例如:

01234
CCCCC

suffix array:
01234
43210
CCCCC
 CCCC
  CCC
   CC
    C

i: 4 -> 5 new substrings
i: 3 -> lcp(3,4) = len(3) no new substrings
i: 2 -> lcp(2,3) = len(2) no new substrings
i: 1 -> lcp(1,2) = len(1) no new substrings
i: 0 -> lcp(0,1) = len(0) no new substrings

total: 5 distinct substrings

第二个示例:

01234
ABABA

suffix array:
01234
42031
AAABB
 BBAA
 AA B
  B A
  A

i: 4 -> 4 new substrings
i: 3 -> lcp(3,4) = len(3) no new substrings
i: 2 -> 5 new substrings
i: 1 -> lcp(1,2) = len(1) no new substrings
i: 0 -> lcp(0,1) = len(0) no new substrings

total: 9 distinct substrings

答案 1 :(得分:0)

要节省空间,请使用std::string_view重用字符串的空间并将其存储在std::unordered_set容器中。应该足以处理内存浪费的问题。