前缀统计 [Trie]

前缀统计

描述

给定N个字符串S1,S2...SN,接下来进行M次询问,每次询问给定一个字符串T,求S1~SN中有多少个字符串是T的前缀。输入字符串的总长度不超过10^6,仅包含小写字母。

输入格式

第一行两个整数N,M。接下来N行每行一个字符串Si。接下来M行每行一个字符串表示询问。

输出格式

对于每个询问,输出一个整数表示答案

样例输入

3 2
ab
bc
abc
abc
efg

样例输出

2
0

题解

trie树操作,把这n个字符串插入到trie中,并更新一下节点信息
在这道题中,每个节点只需要保存cnt表示当前节点是多少个字符串的末尾节点,那么如果被询问的字符串T匹配到当前节点,表示从T的首字符开始到当前一直是匹配的,那么我们在查询过程中累加节点的cnt值就可以了
中间注意判断一下,如果trie已经搜到了叶子节点还要但匹配还没有完成,直接return ans

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
#define in(i) (i=read())
using namespace std;
int read() {
    int ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    while(i>='0' && i<='9') {ans=(ans<<1)+(ans<<3)+i-'0'; i=getchar();}
    return ans*f;
}
int n,m,tot;
int trie[1000010][27],cnt[1000010];
void insert(char* str) {
    int len=strlen(str),p=0;
    for(int i=0;i<len;i++) {
        int ch=str[i]-'a';
        if(!trie[p][ch]) trie[p][ch]=++tot;
        p=trie[p][ch];
    }
    cnt[p]++;
}
int search(char* str) {
    int ans=0;
    int len=strlen(str),p=0;
    for(int i=0;i<len;i++) {
        int ch=str[i]-'a';
        p=trie[p][ch];
        if(!p) return ans;
        ans+=cnt[p];
    }
    return ans;
}
int main()
{
    char s[1000010];
    in(n); in(m);
    for(int i=1;i<=n;i++) {
        scanf("%s",s); insert(s);
    }
    for(int i=1;i<=m;i++) {
        scanf("%s",s);
        printf("%d\n",search(s));
    }
    return 0;
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

posted @ 2018-07-25 20:14  real_l  阅读(902)  评论(0编辑  收藏  举报