[BZOJ]1819: [JSOI]Word Query电子字典 trie+链表

Description

人们在英文字典中查找某个单词的时候可能不知道该单词的完整拼法,而只知道该单词的一个错误的近似拼法,这时人们可能陷入困境,为了查找一个单词而浪费大量的时间。带有模糊查询功能的电子字典能够从一定程度上解决这一问题:用户只要输入一个字符串,电子字典就返回与该单词编辑距离最小的几个单词供用户选择。 字符串a与字符串b的编辑距离是指:允许对a或b串进行下列“编辑”操作,将a变为b或b变为a,最少“编辑”次数即为距离。  删除串中某个位置的字母;  添加一个字母到串中某个位置;  替换串中某一位置的一个字母为另一个字母; JSOI团队正在开发一款电子字典,你需要帮助团队实现一个用于模糊查询功能的计数部件:对于一个待查询字符串,如果它是单词,则返回-1;如果它不是单词,则返回字典中有多少个单词与它的编辑距离为1。

题解:

直接建个trie暴力搞就好了,再用个链表,这样删除、插入、修改都能快速完成。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Maxn=10010;
const int Maxl=25;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,tot=0,Next[Maxl],Last[Maxl],st,ed,T[Maxn*20],ti=0;
char str[Maxl];
struct Trie{int son[27];bool tf;}tr[Maxn*20];
void build_trie()
{
    int now=0,len=strlen(str);
    for(int i=0;i<len;i++)
    {
        int x=str[i]-'a'+1;
        if(!tr[now].son[x])tr[now].son[x]=++tot;
        now=tr[now].son[x];
    }tr[now].tf=true;
}
bool work(char *str)
{
    int now=0,len=strlen(str);
    for(int i=st;i!=ed;i=Next[i])
    {
        int x=str[i]-'a'+1;
        if(!tr[now].son[x])return false;
        now=tr[now].son[x];
    }
    if(tr[now].tf)
    {
        if(T[now]!=ti){T[now]=ti;return true;}
        return false;
    }return false;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str);
        build_trie();
    }
    while(m--)
    {
        for(int i=0;i<=20;i++)Next[i]=i+1,Last[i]=i-1;st=0;ed=-1;
        scanf("%s",str);ti++;
        int len=strlen(str),ans=0;
        Next[len-1]=-1;
        if(work(str)){Next[len-1]=len;puts("-1");continue;}
        for(int i=0;i<len;i++)
        for(int j=0;j<26;j++)
        if(str[i]!=j+'a')
        {
            char t=str[i];
            str[i]=j+'a';
            if(work(str))ans++;
            str[i]=t;
        }//改字符
        for(int i=0;i<len;i++)
        {
            int yl,yn;
            if(i==0)st=1;
            else if(i==len-1)ed=len-1;
            else
            {
                yl=Last[i];yn=Next[i];
                Next[yl]=yn;Last[yn]=yl;
            }
            if(work(str))ans++;
            if(i==0)st=0;
            else if(i==len-1)ed=-1;
            else Next[yl]=Last[yn]=i;
        }//删字符
        for(int i=0;i<len;i++)//在这个字符前面加 
        {
            if(i==0)
            {
                st=len;
                Next[st]=0;
                for(int j=0;j<26;j++)
                {
                    char c=j+'a';
                    str[st]=c;
                    if(work(str))ans++;
                }st=0;
            }
            else
            {
                for(int j=0;j<26;j++)
                {
                    char c=j+'a';
                    str[len]=c;
                    int yl=Last[i];
                    Next[yl]=len;Next[len]=i;
                    if(work(str))ans++;
                    Next[yl]=i;Next[len]=-1;
                }
            }
        }//加字符 
        Next[len-1]=len;Next[len]=-1;
        for(int j=0;j<26;j++)
        {
            char c=j+'a';
            str[len]=c;
            if(work(str))ans++;
        }
        printf("%d\n",ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值