1. 程式人生 > >HDU6170 字串DP/正則表示式

HDU6170 字串DP/正則表示式

Two strings

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2573    Accepted Submission(s): 912

 

Problem Description

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

多校重現,虐,嚶(一下午一道題可還行嚶

題意:第一段是隻有字母的字串,第二段是有字母以及特殊字元的字串,'.'可以代替任意字元,'*'可以使它前一位的字元出現任意次數,甚至是0次(此時即*及其前面的字元匹配空字串),問兩串字串是否匹配。

可能情況太多,在匹配前面的時候永遠不知道後面有什麼情況,用dp陣列,dp[i][j]表示到字串1第i位與字串2第j位(前i與前j)的匹配情況:

1)s2[j]為'.'或者是與s1[i]匹配的字元,dp[i][j]=max(dp[i-1][j-1],dp[i][j]);

2)s2[j]為'*',情況比較多,比較複雜:

a.如果是在第二位,單獨將dp[0][2]置1;

b.如果'*'之前兩位的s2[j-2]與s1[i]及其之前都匹配,那麼j位也匹配,此時即s2[j-1]出現0次,匹配空字串。例如:ab與abb*。可以得出:dp[j][i]=max(dp[j][i],dp[j-2][i]);

c.如果'*'跟隨的s2[j-1]與s1[i]及其之前都匹配,那麼j位也匹配,此時即s2[j-1]出現1次。例如:ab與ab*。可以得出:dp[j][i]=max(dp[j][i],dp[j-1][i]);

d.如果s2[j-1]與s1[i-1]及其之前都匹配,且s1[i]=s1[i-1],此時即s2[j-1]出現2次。例如:abb與ab*。可以得出:dp[j][i]=max(dp[j][i],dp[j-1][i-1]||s1[i]==s1[i-1]);

e.如果s2[j]與s1[i-1]及其之前都匹配,且s2[j-1]與s1[i]匹配,此時即s2[j-1]出現3次及以上。例如:abbbbb與ab*。可以得出:dp[j][i]=max(dp[j][i],dp[j][i-1]&&(s2[j-1]==s1[i]||s2[j-1]=='.'&&s1[i-1]==s1[i]));

注:e情況不可單純寫s1[i]==s1[i-1],例aa與ab*,因為dp[j][i-1]=1且s1[i]=s1[i-1],就無法返回正確答案(雖然辣雞HDU資料太弱一樣ac)

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxs=2500;

int dp[maxs+10][maxs+10];

int main()
{
    int t;
    char s1[maxs+10],s2[maxs+10];
    int i,j,l1,l2;

    scanf("%d",&t);
    while(t--){
		memset(dp,0,sizeof(dp));
		scanf("%s",s1+1);
		scanf("%s",s2+1);
		l1=strlen(s1+1);
		l2=strlen(s2+1);
		dp[0][0]=1;
		if(s2[2]=='*') dp[2][0]=1;	  //!!
		for(j=1;j<=l2;++j){
//			if(s2[j]=='*'){
//				dp[j][0]=max(dp[j][0],dp[j-2][0]);
//			}	//開頭沒遍歷過0
			for(i=1;i<=l1;++i){
				if(s1[i]==s2[j]||s2[j]=='.'){
					dp[j][i]=max(dp[j][i],dp[j-1][i-1]);
				}
				else if(s2[j]=='*'){
					dp[j][i]=dp[j-1][i]		//ab ab*
							 ||dp[j-1][i-1]&&s1[i]==s1[i-1]	   //abbbb ab* 第2個b
							 ||dp[j][i-1]&&(s2[j-1]==s1[i]||s1[i]==s1[i-1]&&s2[j-1]=='.')	  //abbbb ab* 第3個之後的b
							 ||dp[j-2][i];	   //abb abbb*
				}
			}
		}
		if(dp[l2][l1]) printf("yes\n");
		else printf("no\n");
    }

    return 0;
}

後來發現,這道題還有一種超級牛逼的做法:正則表示式。

題意和正則表示式一樣啊嚶~

有點難理解,姑且看看大牛們的程式碼,如下:

#include <cstdio>
#include <string>
#include <iostream>
#include <regex>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);	//關閉同步輸出流
	int t;

	cin>>t;
	while(t--){
		string s1,s2;
		cin>>s1>>s2;
		s2=regex_replace(s2,regex("\\.\\*"),"(.)\\1*");		//因為正則表示式中的.*是可以代替任意長度任意字元而題目要求某一相同字元任意長度
		regex_match(s1,regex(s2))?cout<<"yes"<<endl:cout<<"no"<<endl;
	}

	return 0;
}