题意:
给两个字符串,第一个串全部由字母组成。第二个串由字母和'.'和'*'组成,其中'.'可以代替任何字母,A*代表字母A可以为任意个数,也可以为空,注意可能存在".*"这种情况,另外题目保证*不会单独出现。
思路:
乍一看像个思维题,但情况太多了,分析分析会发现具有状态转移性质。令第二个串为s1,第一个串为s2。
DP[i][j]表示s1串前i个字符去匹配s2串前j个字符能否成功。
所以我们第一层枚举s1的长度,第二层枚举s2的长度进行操作就好。不过存在'*'时的情况有点复杂,注意细节就好了,我的思路细节看代码。。
代码:
#include <bits/stdc++.h>
const int maxn = 2505;
bool dp[maxn][maxn];
char s1[maxn], s2[maxn];
int main()
{
//freopen("in.txt", "r", stdin);
int t; scanf("%d", &t);
while(t--)
{
scanf("%s %s", s2+1, s1+1);
int len1 = strlen(s1+1), len2 = strlen(s2+1);
memset(dp, 0, sizeof dp);
dp[0][0] = 1; s1[0] = s2[0] = '@';
for(int i = 2; i <= len1 && s1[i] == '*'; i+=2) dp[i][0] = 1;
//我的这个预处理在我代码中是关键。代表前面若干A*(任意字母和*)都可以完全不匹配字符
for(int i = 1; i <= len1; ++i)
{
int keep = 1, tmp;
for(int j = 1; j <= len2; ++j)
{
//字母和'.'的情况直接转移
if(s1[i] != '.' && s1[i] != '*')
{
dp[i][j] = (dp[i-1][j-1] && s1[i] == s2[j]);
}
else if(s1[i] == '.')
{
dp[i][j] = dp[i-1][j-1];
}
else
{
dp[i][j] = dp[i-2][j];//代表A*段可以不匹配字符
if(s1[i-1] == '.')
{
if(keep == 1) tmp = dp[i-2][j-1];
else tmp = (tmp||dp[i-2][j-1]);
dp[i][j] = (tmp||dp[i][j]);
}
else if(s1[i-1] == s2[j])
{
if(keep == 1) tmp = dp[i-2][j-1];
else tmp = (tmp||dp[i-2][j-1]);
dp[i][j] = (tmp||dp[i][j]);
}
}
if(s2[j+1] == s2[j]) ++keep;
else keep = 1;
//keep代表s2串到达j时与其直接的前面重复的个数
//用于优化上述A*时确定dp[i][j]
//个数不为1时A*情况可以从前面若干个位置转移过来,所以上述优化减掉了一个for循环
}
}
if(dp[len1][len2]) puts("yes");
else puts("no");
}
return 0;
}
继续加油~