题目地址:http://acm.uestc.edu.cn/problem.php?pid=1616
题目分析:两个字符串a,b,其中b仅由大写英文字母构成,a除了有大写英文字母,还有‘*’,‘?’;判断a能否是b的子串。其中:
‘*’:表示此处有若干个待辨识的字符(可以是0个!);
‘?’:表示此处恰有一个待辨识的字符。
解题思路:这个问题中包含着相同结构的子问题:
若a[i]及之前的子串已经和b[k]及之前的子串匹配上了,并且a[i+1]是‘*’,
那么如果以a[i+1]和b[k+1]开始的子串匹配上,整个串就匹配上了!详见代码注释。。。。。。
源代码:
#include<cstdio>
#include<cstring>
bool check(char a[2000],char b[2000])
{
int lena,lenb,i,j,k,p,sign,num;
lena=strlen(a);
lenb=strlen(b);
if(lena==0)//特判1:判断a是否为空?若为空,a就是b的子串!
return true;
for(i=0;i<lena;i++)
if(a[i]!='*')
break;
if(i==lena) //特判2:判断a是否全是‘*’,若是,a就是b的子串!
return true;
if(lenb==0 && lena>0)//特判3:如果b串是空串,a一定不是b的子串!
return false;
for(i=0;i<lena;i++)
if(a[i]!='*' && a[i]!='?')//找到a中第一个不是'*'和'?'的字符的位子p
{
p=i;
break;
}
num=0;
for(j=p-1;j>=0;j--)//统计p之前有多少个'?',存在num中
{
if(a[j]=='?')
num++;
}
for(i=0;i<lenb;i++)//b串从前往后扫。。。
{
if(a[p]==b[i])//如果和a第一个字母匹配。。。
{
if(i>=num)//并且b串在字符i之前已包含足够多的字符来满足a串中的‘?’
{
sign=0;
for(j=p+1,k=i+1; j<lena && k<lenb; j++,k++)//a和b字符开始逐一匹配。。。
{
if(a[j]==b[k])//又匹配上一个,继续!
continue;
else if(a[j]>='A' && a[j]<='Z')//一个字符没匹配上,那肯定匹配不上咯。。。
{
sign=1;//信号量:没匹配上!
break;
}
else if(a[j]=='?')//a串在这里有一个带辨识的字符,随便b这里是什么吧,继续!
continue;
else if(check(a+j,b+k)==true)//这种情况就是a这里是'*'了,看后面的子串是否匹配上,相同结构的子问题!递归!
{
j=lena;//表示a串匹配完了,j到达lena是在递归调用中完成的,这里让它直接到头就是了!
break;
}
}
if(sign==0)//上面循环结束前没出现匹配错误。。。
{
if(j==lena)//并且a中全部字符都匹配完了!!!
return true;
}
}
}
}
return false;
}
int main()
{
int t;
char a[2000],b[2000],ch;
scanf("%d",&t);
while(t--)
{
scanf("%c",&ch);
while(ch!='\n')
scanf("%c",&ch);
scanf("%s%s",a,b);
if(check(a,b)==true)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}