题意:给你两个字符串,第一个是普通的字符串,第二个中含有“点”和 “星”,“点”可以匹配任意一个字符,“星”可以让它前面的字符出现若干次。问你两个字符能不能匹配。
分析:我是用dp 写的,类似于最长公共子序列。状态开了三维,其实开两维就可以。f[i][j][k] 表示 第一个字符的前i个字符和第二个字符串的前j个字符匹配。k = 0 表示 字符和字符匹配,k = 1表示点和字符匹配,k = 3表示星和字符匹配,其实这一维是没必要的。转移的时候星比较特殊。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int N = 2505;
bool f[N][N][3];
string s1, s2;
int main(){
int T;
cin >> T;
while(T--){
memset(f, 0, sizeof(f));
cin >> s1 >> s2;
s1 += '#', s2 += '#';
int len1 = s1.length();
int len2 = s2.length();
f[0][0][0] = f[0][0][1] = f[0][0][2] = true;
for(int i = 0; i < len1; i++){
for(int j = 0; j < len2; j++){
if(s1[i] == s2[j] && (isalpha(s1[i]) || s1[i] == '#')){
f[i + 1][j + 1][0] = f[i + 1][j + 1][0] || f[i][j][0] || f[i][j][1]|| f[i][j][2];
if(j >= 1 && s2[j - 1] == '*'){
f[i + 1][j + 1][2] = f[i + 1][j + 1][2] || f[i][j - 2][0] || f[i][j - 2][1] || f[i][j - 2][2];
f[i + 1][j + 1][2] = f[i + 1][j + 1][2] || f[i][j - 1][0] || f[i][j - 1][1] || f[i][j - 1][2];
}
}else if(s2[j] == '.'){
f[i + 1][j + 1][1] = f[i + 1][j + 1][1] || f[i][j][0] || f[i][j][1]|| f[i][j][2];
if(j >= 1 && s2[j - 1] == '*'){
f[i + 1][j + 1][2] = f[i + 1][j + 1][2] || f[i][j - 2][0] || f[i][j - 2][1] || f[i][j - 2][2];
f[i + 1][j + 1][2] = f[i + 1][j + 1][2] || f[i][j - 1][0] || f[i][j - 1][1] || f[i][j - 1][2];
}
}else if(s2[j] == '*'){
if(j == 0) f[i][j][2] = 0;
else if(s1[i] == s1[i - 1]){
f[i + 1][j + 1][2] = f[i + 1][j + 1][2] || f[i][j][0] || f[i][j][1]|| f[i][j + 1][2] || f[i][j][2];
}
}
}
}
int yes = 0;
if(f[len1][len2][0] || f[len1][len2][1] || f[len1][len2][2]) yes = 1;
if(yes) puts("yes");
else puts("no");
}
return 0;
}
/*
abcdddddbbc
a..d*.bb*
*/