【dp】或者玄学【库函数】?Two strings HDU - 6170 【正则匹配字符串】
Giving two strings and you should judge if they are matched.
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 “”.
Input
The first line contains an integer T implying the number of test cases. (T≤15)
For each test case, there are two lines implying the two strings (The length of the two strings is less than 2500).
Output
For each test case, print “yes” if the two strings are matched, otherwise print “no”.
Sample Input
3
aa
a*
abb
a.*
abb
aab
Sample Output
yes
yes
no
题意:
给出两个串s1,s2。
s1只含字母,s2含字母和.
*
.
可以和任何一个字母匹配
*
表示其前面一个字符可以出现0 ~ n次
*
不可能出现在字符串首位,不可能出现连续的*
如果两个串可以匹配,那么输出yes,否则输出no
方法一:dp
思路:
dp[i][j]
表示s1的前i位和s2前j位是否匹配。
那么分为以下三种可能:
s2[j]
为字母 ,则
- 如果
s1[i] = s2[j]
那么dp[i][j]
由dp[i - 1][j - 1]
转化而来,如果s1的前i - 1位和s2前j - 1位匹配,那么s1的前i位和s2前j位也匹配,否则不匹配,即dp[i][j] = dp[i - 1][j - 1]
- 如果
s1[i] != s2[j]
,则dp[i][j] = 0
- 如果
s2[j]
为.
,则 不管s1[i]
是哪个字母,都可以匹配,那么dp[i][j]
由dp[i - 1][j - 1]
转化而来,即dp[i][j] = dp[i - 1][j - 1]
s2[j]
为*
,那么s2[j - 1]
可以出现0次,1次,2次及以上次。- 出现0次,即
s2[j - 1]
和s2[j]
都没有了,相当于去掉两位,dp[i][j]
由dp[i][j - 2]
转化而来,即dp[i][j] = dp[i][j - 2]
- 出现1次,即
s2[j - 1]
存在,s2[j]
没有了,相当于第j位是空的,dp[i][j]
由dp[i][j - 1]
转化而来,即dp[i][j] = dp[i][j - 1]
- 出现2次,相当于
s2[j - 1]
重复了一次,如果s1能够和s2匹配,那么s1此处必须有重复的字母,即s1[i - 1] == s1[i]
且要求s2[j - 1] = s1[i]
,那么此时dp[i][j]
由dp[i - 1][j - 1]
,即dp[i][j] = dp[i - 1][j - 1]
- 出现2次以上,相当于把
s2[j - 1]
重复很多次,那么这个前提条件当然是s1[i - 1] == s1[i]
且要求s2[j - 1] = s1[i]
(即出现两次的条件),同时和出现两次的区别是还要保留*
,才可以再重复出现几次,而不仅仅出现两次,此时dp[i][j]
由dp[i - 1][j]
(保留∗) ( 保 留 ∗ ) ,即dp[i][j] = dp[i - 1][j - 1]
综上
s2[j]
约束条件 dp[i][j]
字母 s2[j] == s1[i]
dp[i - 1][j - 1]
字母 s2[j] != s1[i]
dp[i - 1][j - 1]
.
dp[i - 1][j - 1]
*
dp[i][j - 1]【0次】 或 dp[i][j - 2] 【1次】
*
s1[i - 1] == s1[i]
dp[i][j - 1]【0次】或 dp[i][j - 2]【1次】或dp[i][j - 1]【2次】 或 dp[i][j - 2]【n次】
- 出现0次,即
AC代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <algorithm>
using namespace std;
const int maxn = 2505;
int dp[maxn][maxn], t;
char s1[maxn], s2[maxn];
int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%s%s", s1 + 1, s2 + 1);
memset(dp, 0, sizeof(dp));
int l1 = strlen(s1 + 1), l2 = strlen(s2 + 1);
dp[0][0] = 1;
if(l2 >= 2 && s2[2] == '*')
dp[0][2] = 1;
for(int i = 1; i <= l1; i++)
{
for(int j = 1; j <= l2; j++)
{
if(isalpha(s2[j]))
{
if(s2[j] == s1[i])
dp[i][j] = dp[i - 1][j - 1];
else
dp[i][j] == 0;
}
else if(s2[j] == '.')
dp[i][j] = dp[i - 1][j - 1];
else
{
dp[i][j] = (dp[i][j - 1] | dp[i][j - 2]);
if(s1[i - 1] == s1[i])
dp[i][j] = (dp[i][j] | dp[i - 1][j - 1] | dp[i - 1][j]);
}
}
}
if(dp[l1][l2])
printf("yes\n");
else
printf("no\n");
}
return 0;
}
方法二:正则表达式 regex库
思路:
regex提供的regex_match函数可以进行正则匹配,但是其规则和题目所给要求有些不同,库函数提供的*
可以匹配任意字符出现n次,如 库函数中.*
模式串可以匹配abcde
这样的字符串,按题意.*
的意思是相同字符的0个或多个重复串。因此需要将.*
替换为(.)\\1*
,()表示分成一个组,\1表示选取第一个组。regex_replace(string 字段, regex 要替换的字段, string替换成什么)可以实现替换,其中regex为正则表达式类.
和*
都有含义,因此需要进行转义。
b=regex_replace(b, regex("\\.\\*"), "(.)\\1*")
再使用regex_match(string 字符串,regex 正则表达式)进行匹配。
AC代码:
#include <iostream>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <regex>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
string a, b;
cin>>a>>b;
b = regex_replace(b,regex("\\.\\*"),"(.)\\1*");
regex_match(a, regex(b)) ? cout<<"yes"<<endl : cout<<"no"<<endl;
}
return 0;
}