Now give you a text and a pattern, you should judge whether the pattern matches the text or not.
The text is a non-empty string and its size is less than 100,000, so do the pattern.
abcdef a*c*f
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");
}
}