Description
人们在英文字典中查找某个单词的时候可能不知道该单词的完整拼法,而只知道该单词的一个错误的近似拼法,这时人们可能陷入困境,为了查找一个单词而浪费大量的时间。带有模糊查询功能的电子字典能够从一定程度上解决这一问题:用户只要输入一个字符串,电子字典就返回与该单词编辑距离最小的几个单词供用户选择。 字符串a与字符串b的编辑距离是指:允许对a或b串进行下列“编辑”操作,将a变为b或b变为a,最少“编辑”次数即为距离。 删除串中某个位置的字母; 添加一个字母到串中某个位置; 替换串中某一位置的一个字母为另一个字母; JSOI团队正在开发一款电子字典,你需要帮助团队实现一个用于模糊查询功能的计数部件:对于一个待查询字符串,如果它是单词,则返回-1;如果它不是单词,则返回字典中有多少个单词与它的编辑距离为1。
Input
第一行包含两个正整数N (N < = 10,000)和M (M < = 10,000)。 接下来的N行,每行一个字符串,第i + 1行为单词Wi。单词长度在1至20之间。再接下来M行,每行一个字符串,第i + N + 1表示一个待查字符串Qi。待查字符串长度在1至20之间。Wi和Qi均由小写字母构成,文件中不包含多余空格。所有单词互不相同,但是查询字符串可能有重复。 提示:有50%的数据范围:N < = 1,000,M < = 1,000。
Output
输出应包括M行,第i行为一个整数Xi。Xi = -1表示Qi为字典中的单词;否则Xi表示与Qi编辑距离为1的单词的个数。
将单词建立trie,对每个查询若不是单词则构造与其编辑距离为1的所有字符串并在trie查询。
由于编辑距离为1的串可能重复,一个单词可能匹配到多次,注意判重。
查询最坏时间复杂度O(M*202*26)
#include<cstdio> #include<cstring> int n,m; char s[32],s1[32]; int nx[200005][26],p=2; bool e[200005]; int d[200005],now=1; void insert(char*s){ int w=0,c; while(*s){ c=*s-'a'; if(nx[w][c])w=nx[w][c]; else w=nx[w][c]=p++; s++; } e[w]=1; } int find(char*s){ int w=0,c; while(*s){ c=*s-'a'; if(nx[w][c])w=nx[w][c]; else return 0; s++; } if(e[w]&&d[w]!=now){ d[w]=now; return 1; } return 0; } int main(){ scanf("%d%d",&n,&m); while(n--){ scanf("%s",s); insert(s); } while(m--){ now++; scanf("%s",s); if(find(s))puts("-1"); else{ int l=strlen(s),ans=0; for(int i=0;i<l;i++){ char c=s[i]; for(char a='a';a<='z';a++){ s[i]=a; if(a!=c)ans+=find(s); } s[i]=c; } for(int i=1;i<l;i++)s1[i-1]=s[i];s1[l-1]=0; ans+=find(s1); for(int i=1;i<l;i++){ s1[i-1]=s[i-1]; ans+=find(s1); } for(int i=0;i<l;i++)s1[i+1]=s[i];s1[l+1]=0; for(int i=0;i<=l;i++){ for(char a='a';a<='z';a++){ s1[i]=a; ans+=find(s1); } s1[i]=s1[i+1]; } printf("%d\n",ans); } } return 0; }