题目链接:https://codeforces.com/problemset/problem/514/C
题目大意:给n个串,再有m次查询,每次查一个串,问n个串中是否存在串与该串长度相同且恰有一个字母不同
题目思路:
1.hash
将n个串通过3的种子转换成hash,以1e8+3为模,a b c分别为0 1 2,然后每个串都会被转换成一个特定的数字。然后对于查询,每次查询都先将查询的串转换成对应的hash值,然后每一位都有对应对hash的影响,减掉后加上假设这一位是另外两个字符时的值,看map中是否有这个值,如果全都没有就是no,有一个有就是yes。由于指数爆炸,所以这种算法在一定概率下还是会导致两个不同的字符串拥有相同的值,所以这种做法还是不推荐。
2.字典树
直接将n个字符串插入字典树,然后对查询的串进行dfs,三种情况,要是跟当前字符一样,就不用花改变次数,如果不一样就需要花,如果不一样但是没次数了那就不能继续。如果有串能够遍历到最后,且该串在n个字符串中有,也就是num[root]!=0,那么就是可以。
以下是代码:
1.hash
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
using namespace std;
const int MAXN =6e5+5;
const ll MOD = 1e18+3;
int n,m;
char s[MAXN];
map<ll,int>mp;
ll p[MAXN];
ll Hash(char s[]){
int len=strlen(s);
ll ans=0;
rep(i,0,len-1){
ans=(ans*3ll%MOD+s[i]-'a')%MOD;
}
return ans;
}
int main()
{
p[0]=1;
rep(i,1,6e5+1){
p[i]=((p[i-1])*3ll)%MOD;
}
while(~scanf("%d%d",&n,&m)){
mp.clear();
ll temp;
rep(i,1,n){
scanf("%s",s);
temp=Hash(s);
mp[temp]=1;
}
int flag;
rep(i,1,m){
scanf("%s",s);
flag=0;
int len=strlen(s);
ll h=Hash(s);
rep(j,0,len-1){
ll temp=(h-(s[len-j-1]-'a')*p[j]+MOD)%MOD;
rep(k,'a','c'){
if(k==s[len-j-1])continue;
ll pp=(temp+(k-'a')*p[j]+MOD)%MOD;
if(mp[pp]){
flag=1;
break;
}
}
}
if(flag)printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
2.字典树
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN =1e6+5;
int n,m,tot,flag;
int trie[MAXN][3],num[MAXN];
char s[MAXN];
void Insert(char s[]){
int len=strlen(s);
int root=0;
rep(i,0,len-1){
int t=s[i]-'a';
if(!trie[root][t])trie[root][t]=tot++;
root=trie[root][t];
}
num[root]++;
}
void dfs(char s[],int root,int l,int r,int p){
if(l==r&&num[root]){
if(!p)flag=1;
return;
}
int t=s[l]-'a';
rep(i,0,2){
if(t==i){
if(trie[root][t])dfs(s,trie[root][t],l+1,r,p);
}
else{
if(trie[root][i]&&p)dfs(s,trie[root][i],l+1,r,p-1);
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
memset(num,0,sizeof(num));
tot=1;
rep(i,1,n){
scanf("%s",s);
Insert(s);
}
rep(i,1,m){
scanf("%s",s);
flag=0;
int len=strlen(s);
dfs(s,0,0,len,1);
if(flag)printf("YES\n");
else printf("NO\n");
}
}
return 0;
}