常见的通配符有以下两种:
*
:可以匹配
0
0
0个及以上的任意字符?
:可以匹配一个任意字符给定一个由通配符和小写字母组成的字符串 S S S和 n n n个由小写字母组成的字符串 T i T_i Ti?,求每个 T i T_i Ti?能否被通配字符串 S S S通配。
1 ≤ n ≤ 100 1\leq n\leq 100 1≤n≤100
字符串长度不超过 1 0 5 10^5 105,通配符个数不超过 10 10 10
依题意,通配符个数不超过 10 10 10,那么我们可以以通配符为界限,将通配串分为若干段。
设通配串能分为
m
m
m段(也就是有
m
?
1
m-1
m?1个通配符),
o
p
i
op_i
opi?表示第
i
i
i段之前的通配符(
0
0
0表示没有,
1
1
1表示?
,
2
2
2表示*
),
l
e
n
i
len_i
leni?表示第
i
i
i段的长度。
对于每个 T k T_k Tk?,我们考虑如何判断其能否被通配字符串通配。设 f i , j f_{i,j} fi,j?表示第 i i i段的结尾能否匹配上 T k T_k Tk?的第 j j j个字符。那么,转移方程为
f i , j = { f i ? 1 , j ? l e n i o p i = 0 f i ? 1 , j ? l e n i ? 1 o p i = 1 ∑ t = 0 j ? l e n i f i ? 1 , k o p i = 2 f_{i,j}= \left\{\begin{matrix} f_{i-1,j-len_i} &op_i=0 \\ f_{i-1,j-len_i-1} &op_i=1 \\ \sum\limits_{t=0}^{j-len_i}f_{i-1,k} &op_i=2 \end{matrix}\right. fi,j?=? ? ??fi?1,j?leni??fi?1,j?leni??1?t=0∑j?leni??fi?1,k??opi?=0opi?=1opi?=2?
用哈希来判断能否转移即可。
答案为 f m , ∣ T k ∣ f_{m,|T_k|} fm,∣Tk?∣?。
时间复杂度为 O ( ∣ S ∣ + m ∑ ∣ T k ∣ ) O(|S|+m\sum|T_k|) O(∣S∣+m∑∣Tk?∣)。
#include<bits/stdc++.h>
using namespace std;
const int N=100000;
const int base=31;
const long long mod=1e9+7;
int T,s1,t1,w1=0,f[15][N+5];
long long bw[N+5],h[N+5],sf[15][N+5];
char s[N+5],t[N+5];
struct node{
int bg,ed,op;
long long hsh;
}w[15];
void init(){
bw[0]=1;
for(int i=1;i<=N;i++){
bw[i]=bw[i-1]*base%mod;
}
}
void solve_s(){
s1=strlen(s+1);
w[++w1].bg=1;
w[w1].op=0;
for(int i=1;i<=s1;i++){
if(s[i]=='?'||s[i]=='*'){
w[w1].ed=i-1;
w[++w1].bg=i+1;
if(s[i]=='?') w[w1].op=1;
else w[w1].op=2;
}
}
w[w1].ed=s1;
for(int i=1;i<=w1;i++){
w[i].hsh=0;
for(int j=w[i].bg;j<=w[i].ed;j++){
w[i].hsh=(w[i].hsh*base+s[j]-'a'+1)%mod;
}
}
}
void solve_t(){
t1=strlen(t+1);
for(int i=1;i<=t1;i++){
h[i]=(h[i-1]*base+t[i]-'a'+1)%mod;
}
}
long long gthsh(int l,int r){
return (h[r]-h[l-1]*bw[r-l+1]%mod+mod)%mod;
}
void solve_dp(){
for(int i=0;i<=w1;i++){
for(int j=0;j<=t1;j++) sf[i][j]=f[i][j]=0;
}
if(gthsh(1,w[1].ed-w[1].bg+1)!=w[1].hsh) return;
f[1][w[1].ed-w[1].bg+1]=1;
for(int i=2;i<=w1;i++){
sf[i-1][0]=f[i-1][0];
for(int j=1;j<=t1;j++){
sf[i-1][j]=sf[i-1][j-1]|f[i-1][j];
}
int len=w[i].ed-w[i].bg+1;
for(int j=1;j<=t1;j++){
if(w[i].op==1){
if(j-len-1>=0&>hsh(j-len+1,j)==w[i].hsh){
f[i][j]=f[i-1][j-len-1];
}
}
else{
if(j-len>=0&>hsh(j-len+1,j)==w[i].hsh){
f[i][j]=sf[i-1][j-len];
}
}
}
}
}
int main()
{
init();
scanf("%s",s+1);
solve_s();
scanf("%d",&T);
while(T--){
scanf("%s",t+1);
solve_t();
solve_dp();
if(f[w1][t1]) printf("YES\n");
else printf("NO\n");
}
return 0;
}