link:通配符匹配
theme:给定仅由a~z组成的串S,由a~z或 * 或 ?组成的串 P ,其中 ? 可代表任意单个字符,* 可代表0或多个连续字符,问P能否匹配出S?
solution:3种做法。
- 贪心:从左到右遍历过程中,如果S[i]==P[j]或P[j]=='?'则可以直接对应匹配,继续遍历就好了:++i,++j ; 若P[j]=='*",因为'*'可以匹配多个,那到底要匹配几个呢?我们可以记录下开始匹配的位置,然后++j继续比,如果之后i,j对应元素不相等但是之前有*匹配过,则我们可以将j回溯到上一个*的位置(即让上一个*多匹配几个字符)
- 动态规划dp:用dp[i][j]表示 以S中字符i处往后的字符串 与 P中字符j处往后的字符串 能否匹配,则 (1)当P[j]=='?' 时,显然i,j处的字符要对应匹配,所以此时dp[i][j]=dp[i+1][j+1] ; (2) 当P[j]=='*'时,dp[i][j]=dp[i][j+1] || dp[i+1][j] .dp[i][j+1]=1的话表明*可以匹配空,dp[i+1][j]=1时,表示*再在左边多匹配一个S[i] ; (3)当P[j]为普通字符时,dp[i][j] = dp[i+1][j]||dp[i][j+1] 。注意一下初始化的情况,*可以匹配空。
- 回溯dfs:dfd(i,j)表示以S中字符i处往后的字符串 与 P中字符j处往后的字符串 能否匹配。与dp类似,这里不赘述了。
贪心:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Maxn = 1e6+10;
const int Inf = 0x7f7f7f7f;
const int Mod = 1e9+7;
bool check(string s,string p)
{
int ls=s.size(),lp=p.size();
int i=0,j=0,istart=-1,jstart=-1;
while(i<ls)
{
if(j<lp&&(s[i]==p[j]||p[j]=='?'))
++i,++j;
else if(j<lp&&p[j]=='*')
{
istart=i;
jstart=j++;
}
else if(jstart>=0)
{
i=++istart;
j=jstart+1;
}
else
return false;
}
while(j<lp&&p[j]=='*')
++j;
return j==lp;
}
int main(){
string a,b;
while(cin>>a>>b){
if(check(a,b))
cout<<1<<endl;
else
cout<<0<<endl;
}
}
/*
acdcb
a*c?b
ho
ho**
abefcdgiescdfimde
ab*cd?i*de
*/
动态规划dp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Maxn = 1e6+10;
const int Inf = 0x7f7f7f7f;
const int Mod = 1e9+7;
bool check(string s,string p)
{
int ls=s.size(),lp=p.size();
int dp[ls+5][lp+5];
for(int i=ls;i>=0;--i)
for(int j=lp;j>=0;--j)
dp[i][j]=0;
dp[ls][lp]=1;
for(int i=lp-1;i>=0;--i)
if(p[i]=='*'&&dp[ls][i+1])
dp[ls][i]=1;
for(int i=ls-1;i>=0;--i)
for(int j=lp-1;j>=0;--j)
{
if(p[j]=='?')
dp[i][j]=dp[i+1][j+1];
else if(p[j]=='*')
dp[i][j]=dp[i+1][j]||dp[i][j+1];
else
dp[i][j]=dp[i+1][j+1]&&(s[i]==p[j]);
// cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
}
return dp[0][0];
}
int main(){
string a,b;
while(cin>>a>>b){
if(check(a,b))
cout<<1<<endl;
else
cout<<0<<endl;
}
}
/*
acdcb
a*c?b
ho
ho**
*/