<题目链接>
题目大意:
输入n个单词构成单词库,然后进行m次查询,每次查询输入一个单词(注意这些单词只由a,b,c构成),问该单词库中是否存在与当前查询的单词有且仅有一个字符不同的单词。
解题分析:
本题将单词库中所有的单词先建trie树,然后进行容错数为1的字符串匹配,主要是在trie树上跑DFS,具体步骤见代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int M = 6e5+100; 7 typedef long long ll; 8 int n,m; 9 char s[M]; 10 struct Trie{ 11 int cur; 12 Trie *next[3]; 13 Trie(){ 14 cur=-1; 15 for(int i=0;i<=2;i++) 16 next[i]=NULL; 17 } 18 }; 19 Trie *root=new Trie; 20 /*void Insert(){ //为什么这种建树方式会超时,而下面的递归建树不会? 21 Trie *now=root; 22 for(int i=0;i<strlen(s);i++){ 23 int to=s[i]-'a'; 24 if(now->next[to]==0) 25 now->next[to]=new Trie; 26 now=now->next[to]; 27 } 28 now->cur=1; 29 }*/ 30 void Trie_Insert(Trie *now,int loc){ //递归进行Trie树的构建 31 if(s[loc]!='\0'){ 32 int to=s[loc]-'a'; 33 if(now->next[to]==NULL) 34 now->next[to]=new Trie; 35 Trie_Insert(now->next[to],loc+1); 36 } 37 else now->cur=1; 38 } 39 bool dfs(Trie *now,int loc,int num){ //now代表当前Trie树上的节点,loc为当前遍历到的字符串上的字符下标,num代表容错数 40 if(s[loc]=='\0'){ 41 if(num==0&&now->cur==1)return true; //如果在该字符串结束时有且仅有一处错误,则符合条件 42 else return false; 43 } 44 int to=s[loc]-'a'; 45 if(now->next[to]!=NULL){ //1.当前字符与Trie树匹配的情况,只有该字符与当前节点相等,才能继续向下dfs 46 if(dfs(now->next[to],loc+1,num)) 47 return true; 48 } 49 if(num==1){ //2.当前loc处的字符为错误字符时,进行容错处理 50 for(int i=0;i<=2;i++){ 51 if(i!=s[loc]-'a'&&now->next[i]!=NULL) //枚举该节点的子节点a,b,c三种三种字符的不同情况,从中挑选与当前字符不同的情况,继续向下匹配 52 if(dfs(now->next[i],loc+1,0)) //由于当前loc位置为错误字符,所以下面的字符容错数为0 53 return true; 54 } 55 } 56 return false; 57 } 58 int main(){ 59 scanf("%d%d",&n,&m); 60 for(int i=1;i<=n;i++){ 61 scanf("%s",s); 62 //Insert(); 63 Trie_Insert(root,0); 64 } 65 for(int i=1;i<=m;i++){ 66 scanf("%s",s); 67 if(dfs(root,0,1)) 68 printf("YES\n"); 69 else printf("NO\n"); 70 } 71 return 0; 72 }
2018-11-01