【问题标题】:Number of Distinct substring of a string字符串的不同子字符串数
【发布时间】:2019-07-08 04:27:20
【问题描述】:

我正在解决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。

错误:无法将 'temp' 从 'std::__cxx11::string* {aka std::__cxx11::basic_string*}' 转换为 'std::__cxx11::string {aka std::__cxx11::基本字符串}'| ||=== 构建失败: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;
    }

}

【问题讨论】:

  • 首先,我认为循环的复杂度永远不会是 O(n^3),而是 O(n^2)。另外,尝试第二种方法时遇到的错误是什么?
  • error: could not convert 'temp' from 'std::__cxx11::string* {aka std::__cxx11::basic_string&lt;char&gt;*}' to 'std::__cxx11::string {aka std::__cxx11::basic_string&lt;char&gt;}'| ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
  • 在将指针传递给字符串后,大多数函数都不能在字符串上工作,例如 key.length() 或 (*key).length() 给出错误
  • 我想你应该使用更高级的数据结构来解决这个问题。后缀数组似乎是一个不错的选择。但是,如果您只想通过测试,则可以通过比较字符串哈希值而不是 O(n^2) 中的字符串值来解决它。

标签: c++ algorithm substring trie


【解决方案1】:

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

正如其他人在 SPOJ 和 cmets 中所指出的那样,由于输入长度只有 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

【讨论】:

    【解决方案2】:

    为了节省空间,通过使用std::string_view 重复使用字符串的空间并将它们存储在std::unordered_set 容器中。应该足以处理内存浪费的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-12
      • 2012-10-24
      • 1970-01-01
      • 2019-11-19
      • 2022-01-22
      • 2015-04-02
      相关资源
      最近更新 更多