字典树 1204 前缀判定

//本题是一道字典树的模板题
//字典树是一种高效率存储多个字符串的数据结构
//其每个结点的权值代表以该结点结尾的字符串的数量,每条边存储一个字符
//从根结点开始,按某一路径遍历到某一结点,即得到一种字符串,其个数等于当前结点存储的数值
//如从根结点开始,依次走过'a''b''c'三条边到达9号结点,9号结点保存的数字是3
//则得到字符串"abc",其数量为3个 
#include <bits/stdc++.h>

using namespace std;

const int N=2e6+100;

int nex[N][27];//nex[i][0]表示从结点i出发,边为'a'的下一个结点地址(假设字符串全由小写字母构成)
//如1号结点与2号结点间存在一条记录字母'a'的边,则nex[1]['a'-'a']=2 
//如8号结点与9号结点间存在一条记录字母'c'的边,则nex[8]['c'-'a']=9 
int cnt[N];//cnt[i]表示以结点i结尾的字符串的数量,即每个结点的权值 
int idx=2;//用于动态开点,初始时只有一个根结点1 

void insert(char *S)//在字典树中插入字符串S的信息 
{
    int x=1;//x表示结点编号,初始从根结点(1号)开始 
    for(int i=0;S[i]!='\0';i++)//遍历字符串S 
    {
        //先检查x是否存在S[i]的边 
        if(nex[x][S[i]-'a']==0)//从结点x出发,目前还没有记录当前字母的边 
        {
            nex[x][S[i]-'a']=idx++;//则新建一个边记录之,同时动态开点 
        }
        x=nex[x][S[i]-'a'];//到达下一个结点编号
    }    
    //cnt[x]++;
    //最终x到达字符串末尾字符对应的结点上,其计数值加1 
}

bool check(char *T)//在字典树中查找字符串T(计算出现的次数)
{
    int x=1;//x表示结点编号,初始从根结点(1号)开始 
    for(int i=0;T[i]!='\0';i++)//遍历字符串T 
    {
        x=nex[x][T[i]-'a'];//根据当前字符,x不断向下追溯,最终到达结尾
        //若不存在这个字符(记录这个字符的边),则x=0,后续x将一直为0 
    }    
    //return cnt[x];//返回字符串T出现的次数,即结尾字符对应的结点所记录的权值 
    return x;//本题返回x即可,只需判断x是否为0 
}

int main()
{
    int n,m;
    cin>>n>>m;
    while(n--)//N个字符串 
    {
        char S[N];
        cin>>S;
        insert(S);//每输入一个字符串,就将其信息插入字典树 
    }    
    while(m--)//M个询问 
    {
        char T[N];
        cin>>T;
        if(check(T))cout<<"Y"<<endl;//在字典树中找到T,输出Y 
        else cout<<"N"<<endl;//没找到,输出N 
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值