字典树求子串hdu2846

来源:互联网 发布:淘宝联盟如何做推广 编辑:程序博客网 时间:2024/06/17 15:08

点击打开链接

这个题目还是比较有意思的,以往的字典树往往是求解前缀的数量,其实也可以求解子串,不过相应的要付出更多的空间代价。

以abcdabc为例,我们先通过暴力枚举的办法将串拆成,abcdabc, bcdabc,cdabc,dabc,abc,bc,c 拆成这些串后,如果想判断da是不是abcdabc的子串,则只要顺着字典树往下,找到dabc这条路的b节点就可以判断了。

此题是给出一个串,判断这个串是多少个单词的子串,用上上面的方法就可以了,为了防止重复计数,我们可以加一个k标记这条路最近是谁走过的

代码如下,看下就明白了!

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;struct Trie{    Trie *next[26];    int v; //记录此前缀串为多少个单词的子串    int k; //记录此节点最近一次串访问的标号    Trie() { memset(next,0,sizeof(next)); v=0; k=0; }};char word[25];char cop[25];inline void Insert(Trie *p,char s[],int k){    for(int i=0; i<strlen(s); i++) {        int id = s[i]-'a';        if( !p->next[id] ){            p->next[id] = new Trie();        }        p=p->next[id];        if(p->k != k){            p->k = k;            p->v++;        }    }}inline int Count(Trie *p,char s[]){    for(int i=0; i<strlen(s); i++){        int id = s[i]-'a';        if(!p->next[id]){            return 0;        }        p=p->next[id];    }    return p->v;}inline void Free(Trie *rt){    if(!rt) return;    for(int i=0; i<26; i++){        Free(rt->next[i]); rt->next[i]=NULL;    }    delete rt;    rt=NULL;    return;}int main(){#ifdef LOCAL_DEBUG    freopen("input.txt","r",stdin);#endif // LOCAL_DEBUG    int T;    scanf("%d" ,&T);    Trie *root = new Trie();    for(int k=1; k<=T; k++){        scanf("%s" ,word);        for(int i=0; i<strlen(word); i++){            memset(cop,0,sizeof(cop));            strcpy(cop,word+i);            Insert(root,cop,k);        }    }    int N;    scanf("%d" ,&N);    for(int k=1; k<=N; k++){        scanf("%s" ,word);        printf("%d\n" ,Count(root,word));    }    Free(root);    return 0;}


0 0
原创粉丝点击