题目:Wildcard
链接:http://acm.hdu.edu.cn/showproblem.php?pid=3901
题意:给一个原串(只含小写字母)和一个模式串(含小写字母、?、* ,*号可替换为0到无穷个任意字母,?可替换为一个任意字母),问两个字符串是否匹配。
思路:
这是经典题吧。。。
AC自动机。(网上大多代码是错的,用普通kmp是不行的,不知道修改过后可不可以)。
HDU已经加强数据了,可我前一个代码abcd ?显示是YES居然还过了,看来数据还是有点弱啊。
*号的处理是很容易的,只需要把模式串以*号为分界分解开来,然后除了最后一段,其他尽量匹配靠前的原串子串就差不多了,比如ab*cd*ef*gh,那么原串必须以ab开头、gh结尾、然后找到最前的cd、再找到ef,如果互相不重叠就OK。
比较难的是?的处理了,*分解开模式串分别处理。现在,根据?分解,将分解后的字符串(不含?号了)构建AC自动机。
比如串A:abcd?abc?cd?abcd,构建AC自动机,然后在结束点记录他在串A中的位置。
红色为根,黄色为每一个结束点,这里的fail指针与普通AC自动机相同
现在我们创建一个数组cnt,对应原串的每一位,让原串在自动机上跑,如果遇到黄点cnt[当前位置-记录的值+1]++,比如遇到abcd,那说明原串当前位置前四位一定是abcd,满足这一段,而如果有某一个cnt值等于4,就说明他满足了所有段,那么他可以作为串A匹配的起点,a b c d _ a b c _ c d _ a b c d,只有上面这种情况才会使第一个a的cnt值为4,而cnt等于4,当前位就是该次匹配满足的最前位置了。
上一段理解后,题目就可以得解了,注意细节就是了。
AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<math.h> 5 #include<set> 6 #include<map> 7 #include<list> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 #include<string> 12 #include<iostream> 13 #include<algorithm> 14 using namespace std; 15 #define lson rt<<1 16 #define rson rt<<1|1 17 #define N 100010 18 #define M 26 19 #define Mod 1000000007 20 #define LL long long 21 #define INF 0x7fffffff 22 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++) 23 #define For(i,f_start,f_end) for(int i=f_start;i<f_end;i++) 24 #define REP(i,f_end,f_start) for(int i=f_end;i>=f_start;i--) 25 #define Rep(i,f_end,f_start) for(int i=f_end;i>f_start;i--) 26 #define MT(x,i) memset(x,i,sizeof(x)) 27 #define gcd(x,y) __gcd(x,y) 28 const double PI = acos(-1); 29 30 struct Node 31 { 32 vector<int> d; 33 int fail; 34 int next[M]; 35 }v[N]; 36 int vNum; 37 38 void Init() 39 { 40 v[0].fail = -1; 41 FOR(i,0,25){ 42 v[0].next[i]=-1; 43 } 44 vNum=1; 45 } 46 47 int create() 48 { 49 v[vNum].d.clear(); 50 v[vNum].fail=-1; 51 for(int i=0;i<M;i++) v[vNum].next[i]=-1; 52 return vNum++; 53 } 54 55 int getPos(char c) 56 { 57 return c-'a'; 58 } 59 60 int add(char *s) 61 { 62 int i,ret=0,p=0; 63 for(i=0;s[i];i++){ 64 if(s[i]=='?'){ 65 if(p!=0){ 66 ret++; 67 v[p].d.push_back(i); 68 p=0; 69 } 70 } 71 int pos = getPos(s[i]); 72 if(v[p].next[pos]==-1) v[p].next[pos]=create(); 73 p = v[p].next[pos]; 74 } 75 if(p!=0){ 76 ret++; 77 v[p].d.push_back(i); 78 } 79 return ret; 80 } 81 82 queue<int> q; 83 void makeFail() 84 { 85 q.push(0); 86 while(q.size()) 87 { 88 int p=q.front(); 89 q.pop(); 90 for(int i=0;i<M;i++) 91 { 92 if(v[p].next[i]!=-1) 93 { 94 int t=v[p].fail; 95 while(1) 96 { 97 if(t == -1) // p 已经是根了 98 { 99 v[v[p].next[i] ].fail = 0; 100 break; 101 } 102 else if(v[t].next[i] != -1) 103 { 104 v[v[p].next[i] ].fail = v[t].next[i]; 105 break; 106 } 107 else t=v[t].fail; 108 } 109 if(t!=-1){ 110 for(int j=0;j<v[t].d.size();j++){ 111 v[p].d.push_back(v[t].d[j]); 112 } 113 } 114 q.push(v[p].next[i]); 115 } 116 } 117 } 118 } 119 120 int cnt[N]; 121 int match(char *s,char *s1) 122 { 123 Init(); 124 int duan = add(s1); 125 if(duan==0) return 0; 126 127 makeFail(); 128 129 //printf("%s %s %d ",s,s1,duan); 130 131 memset(cnt,0,sizeof(cnt)); 132 int i,p=0; 133 for(i=0;s[i];i++){ 134 int pos = getPos(s[i]); 135 if(p==-1){ 136 p=0; 137 continue; 138 } 139 if(v[p].next[pos]==-1){ 140 p = v[p].fail; 141 i--; 142 continue; 143 } 144 p = v[p].next[pos]; 145 for(int j=0;j<v[p].d.size();j++){ 146 cnt[i-v[p].d[j]+1]++; 147 if(cnt[i-v[p].d[j]+1]==duan) return i-v[p].d[j]+1; 148 } 149 } 150 return -1; 151 } 152 153 char s[N],s1[N],s2[N]; 154 bool solve(char *s,char *s1) 155 { 156 int ls=strlen(s),ps=0; 157 int i,len=0,flag=0; 158 for(i=0;s1[i];i++){ 159 if(s1[i]=='*'){ 160 if(len!=0){ 161 s2[len]=0; 162 int qi = match(s+ps,s2); 163 if(qi==-1) return false; 164 if(flag==0 && qi!=0) return false; 165 ps += qi + len; 166 if(ps>ls) return false; 167 len = 0; 168 } 169 flag=1; 170 } 171 else s2[len++]=s1[i]; 172 } 173 if(len!=0){ 174 len--; 175 for(i=ls-1;i>=ps && len>=0;i--){ 176 if(s2[len]!='?' && s2[len]!=s[i]) return false; 177 len--; 178 } 179 if(i>=ps && flag==0 || len>=0) return false; 180 } 181 return true; 182 } 183 184 int main() 185 { 186 while(scanf("%s%s",s,s1)!=EOF) 187 { 188 printf("%s ",solve(s,s1)?"YES":"NO"); 189 } 190 return 0; 191 }