Two strings
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 0 Accepted Submission(s): 0
The first string contains lowercase letters and uppercase letters.
The second string contains lowercase letters, uppercase letters, and special symbols: “.” and “*”.
. can match any letter, and * means the front character can appear any times. For example, “a.b” can match “acb” or “abb”, “a*” can match “a”, “aa” and even empty string. ( “*” will not appear in the front of the string, and there will not be two consecutive “*”.
For each test case, there are two lines implying the two strings (The length of the two strings is less than 2500).
3 aa a* abb a.* abb aab
yes yes no
题目大意:
给出两个字符串,第一个字符串只包含小写或者大写字母,第二个字符串包含小写或者大写字母或者特殊字符“.”和“*”,这里“.”可以替换为任意字符,但是不能变成空。
这里“a*”可以变成空串,可以变成a,也可以是aa,也可以是aaa,还可以是aaaa.以此类推,不限长度。
问第二个串和第一个串是否能够完全相等。
思路:
观察到数据范围,如果是贪心做法的话,数据范围肯定不能这么小,而且仔细考虑一下,直接贪心O(n)扫显然有纰漏;
那么我们考虑Dp,设定Dp【i】【j】表示串2到位子i,实际匹配串1到位子j的方案是否存在。
那么不难想到其状态转移方程:
①if(b[i]是大写字母或者是小写字母)Dp【i】【j】=Dp【i-1】【j-1】&&(a【i】==a【j】);
②if(b[i]是“.”)Dp【i】【j】=Dp【i-1】【j-1】;
③if(b[i]是“*”):
Dp【i】【j】=max(Dp【i-1】【j】,Dp【i】【j】);
Dp【i】【j】=max(Dp【i-2】【j】,Dp【i】【j】);
Dp【i】【j】=max(Dp【i-1】【k~j-1】,Dp【i】【j】);位子k到位子j-1之间的字符要保证都相等。
我们发现暴力去搞的话时间复杂度最坏可以达到O(n^3),那么我们考虑优化,很显然位子k是可以进行二分的,但是时间复杂度还是O(n^2logn)依然不低,但是我们可以维护一个数组pre【j】,表示和a【j】相等的字符串的最前边的位子,也就是我们的k,可以在Dp的过程维护,那么我们只要再求一个Dp的前缀和优化一下就能够达到O(n)了;那么状态转移方程③可以进行优化为:
Dp【i】【j】=max(Sum【i-1】【j-1】-Sum【i-1】,Dp【i】【j】);位子k到位子j-1之间的字符要保证都相等。
注意初始化,就没有别的什么了。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
char a[2600];
char b[2600];
bool dp[2600][2600];
int pre[2600];
int Is_or[2600][2600];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",a+1);
scanf("%s",b+1);
int n=strlen(a+1);
int m=strlen(b+1);
memset(dp,false,sizeof(dp));
dp[0][0]=true;
for(int i=1;i<=m;i++)
{
for(int j=0;j<=n;j++)
{
if(j==1)pre[j]=j;
else
{
if(a[j]==a[j-1])pre[j]=pre[j-1];
else pre[j]=j;
}
if(b[i]=='.')
{
if(j-1>=0)dp[i][j]=dp[i-1][j-1];
}
else if(b[i]=='*')
{
if(j==0)dp[i][j]=dp[i-1][j];
else
{
int pos=pre[j];
int tmp;
if(Is_or[i-1][j-1]-Is_or[i-1][pos-1]>0)tmp=1;
else tmp=0;
dp[i][j]=tmp;
}
if(i-1>=0)dp[i][j]=max(dp[i][j],dp[i-1][j]);
if(i-2>=0)dp[i][j]=max(dp[i][j],dp[i-2][j]);
}
else
{
if(j-1>=0)dp[i][j]=(dp[i-1][j-1])&&(b[i]==a[j]);
}
if(j==0)Is_or[i][j]=dp[i][j];
else Is_or[i][j]=dp[i][j]+Is_or[i][j-1];
}
}
if(dp[m][n]==true)printf("yes\n");
else printf("no\n");
}
}