hdu 3901 Wildcard 带通配符的字符串匹配

Problem Description
When specifying file names (or paths) in DOS, Microsoft Windows and Unix-like operating systems, the asterisk character (“*") substitutes for any zero or more characters, and the question mark (“?") substitutes for any one character.
Now give you a text and a pattern, you should judge whether the pattern matches the text or not. 
 

Input
There are several cases. For each case, only two lines. The first line contains a text, which contains only lower letters. The last line contains a pattern, which consists of lower letters and the two wildcards (“*", "?").
The text is a non-empty string and its size is less than 100,000, so do the pattern.
 

Output
Output “YES” if the pattern matches the text, otherwise “NO”.
 

Sample Input
abcdef a*c*f
 

Sample Output
YES

//


本题的模式可以表示为S1*S2*…*Sn-1*Sn,其中Si只由小写字母和’?’组成。首先检查S1,Sn是否匹配文本,然后得到的模式变成*S2*…*Sn-1*的形式。这种形式首尾都含有‘*’。然后可以贪心的检查S2… Sn-1 这些片段是否依次出现在文本中,需要使用kmp。若模式串长度为M,文本串长度为N,则此题的时间复杂度为O(M+ N)。


#include<cstdio>
#include<cstring>
using namespace std;


const int maxn = 120000;
char pat[maxn], text[maxn];


int fail[maxn];
//text 是否包含 pat
void makefail(char *t, int lt){
--t;
for(int i = 1, j = 0; i <= lt; i++, j++){
fail[i] = j;
while(j > 0 && t[i] != '?' && t[j] != '?' && t[i] != t[j])
j = fail[j];
}
}
int kmp(char *s, int ls, char *t, int lt, int i){
--s, --t; ++i;
for(int j = 1; i <= ls; i++, j++){
while(j > 0 && t[j] != '?' && s[i] != t[j])j = fail[j];
if(j == lt)return i - lt;
}
return -1;
}


bool wildMatch(char * pat, int lp, char * text, int lt){
//处理不含有 * 的情况
bool star = false;
for(int i = 0; i < lp && !star; i++)
if(pat[i]=='*')star = true;
if(!star){
if(lp != lt)return false;
for(int i = 0; i < lp; i++)
if(pat[i] != '?' && pat[i] != text[i])return false;
return true;
}


//处理前缀和后缀
int l0 = 0, l1 = 0;
for(int i = 0; pat[i] != '*'; i++){
if(i >= lt || pat[i] != '?' && pat[i] != text[i])return false;
l0 ++;
}
for(int i = 0; pat[lp - 1 - i] != '*'; i++){
if(i >= lt || pat[lp - 1 - i] != '?' && pat[lp - 1 - i] != text[lt - 1 - i])
return false;
l1++;
}
if(l0 + l1 > lt)return false;


//处理以*开始并且以*结束的部分
int offP = l0, offT = l0;
for(int i = l0; i < lp - l1; i++){
if(pat[i]=='*'){
int plen = i - offP;
if(plen > 0){
makefail(pat + offP, plen);
int match = kmp(text, lt - l1, pat + offP, plen, offT);
if(match == -1)return false;
offT = match + plen;
}
offP = i + 1;
}
}
return true;
}


int main(){
while( gets(text) )
{
gets(pat);
if( wildMatch(pat, strlen(pat), text, strlen(text) ) )
puts("YES");
else
puts("NO");
}
}

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值