[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/

猜你喜欢

转载自www.cnblogs.com/real-l/p/9368068.html
今日推荐