c++ - 字符串的不同子串数

标签 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) for 循环:O(n^3)。这让我 TLE。

error: could not convert 'temp' from 'std::__cxx11::string* {aka std::__cxx11::basic_string*}' to 'std::__cxx11::string {aka std::__cxx11::basic_string}'| ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

所以我想用这样的东西替换 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;
    }

}

最佳答案

我没有使用 C++ 的经验,但你评论的错误似乎源于编译器在遇到变量 temp 时对它接收的变量类型的不同期望。

正如其他人在 SPOJ 和评论中指出的那样,由于输入长度仅为 256 个字符,因此您可以通过暴力哈希和计算所有子字符串的出现次数来逃脱。

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

例如:

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

关于c++ - 字符串的不同子串数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54685418/

相关文章:

C++ 使对象依赖于其他对象是一个好的设计吗?

c++ - 返回对局部变量的引用

algorithm - 红黑树 - K 插入和 K 删除所需的最大旋转次数?

mysql - 生成两位数不同的唯一代码

.net - ASP.NET VB - .NET 的一些数学运算

c# - 在字符串列表中查找子字符串

c++ - 在现代 C++ 中将 std::array<std::array<T,N>> 转换为 std::vector<T>

c++ - 如何在给定起点和终点的字符串中查找子字符串的出现次数?

Java 子字符串操作似乎导致 Java 1.8 中出现内存不足错误

c++ - 求解线性方程组的最有效方法