几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个
是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符。
现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。
几乎所有操作系统的命令行界面(CLI)中都支持文件名的通配符匹配以方便用户。最常见的通配符有两个,一个
是星号(“”’),可以匹配0个及以上的任意字符:另一个是问号(“?”),可以匹配恰好一个任意字符。
现在需要你编写一个程序,对于给定的文件名列表和一个包含通配符的字符串,判断哪些文件可以被匹配。
第一行是一个由小写字母和上述通配符组成的字符串。
第二行包含一个整数n,表示文件个数。
接下来n行,每行为一个仅包含小写字母字符串,表示文件名列表。
输出n行,每行为“YES”或“NO”,表示对应文件能否被通配符匹配。
对于1 00%的数据
·字符串长度不超过1 00000
· 1 <=n<=100
·通配符个数不超过10
DP+哈希
f[i][j]表示第i个通配符和第j个字符能否匹配,然后搞搞转移,注意两种通配符的区别。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define ull unsigned long long #define maxn 100005 #define base 13131 using namespace std; char ch[maxn],s[maxn]; int n,len,cnt,pos[15]; bool f[15][maxn]; ull n1[maxn],n2[maxn],p[maxn]; inline ull h1(int st,int ed) { if (st>ed) return 0; return n1[ed]-n1[st-1]*p[ed-st+1]; } inline ull h2(int st,int ed) { if (st>ed) return 0; return n2[ed]-n2[st-1]*p[ed-st+1]; } int main() { // freopen("input.in","r",stdin); scanf("%s",ch+1); len=strlen(ch+1); F(i,1,len) if (ch[i]<'a'||ch[i]>'z') pos[++cnt]=i; pos[++cnt]=len+1;ch[++len]='?'; F(i,1,len) n1[i]=(n1[i-1]*base+ch[i]); p[0]=1; F(i,1,100000) p[i]=p[i-1]*base; scanf("%d",&n); while (n--) { scanf("%s",s+1); len=strlen(s+1);s[++len]='#'; F(i,1,len) n2[i]=n2[i-1]*base+s[i]; memset(f,0,sizeof(f)); f[0][0]=true; F(i,0,cnt-1) { if (ch[pos[i]]=='*') { F(j,1,len) if (f[i][j-1]) f[i][j]=true; } F(j,0,len) if (f[i][j]&&h1(pos[i]+1,pos[i+1]-1)==h2(j+1,j+pos[i+1]-pos[i]-1)) { if (ch[pos[i+1]]=='?') f[i+1][j+pos[i+1]-pos[i]]=true; else f[i+1][j+pos[i+1]-pos[i]-1]=true; } } if (f[cnt][len]) puts("YES"); else puts("NO"); } return 0; }