【HDOJ】3901 Wildcard
1. 题目描述
有两个长度为$10^5$的字符串,其中一个仅包含小写字母,称之为源串;另一个包含?与*通配符的模式串,并且通配符的个数不超过10。求模式串是否能匹配源串?
2. 基本思路
这其实是一道RegularExpression-Matching问题。一般化的解法就是构建自动机,然后去在这个自动机上搜索源串,是否被接收即为答案。这个一般化方法的时间复杂度为$O(|x||y|)$。显然,这里不适用。题目中的限定条件通配符个数不超过10使得,不需要构建完整的自动机。我们可以将模式串$d$改写为
$d_0 \cdot (?|*) \cdot d_1 \cdot (?|*) \cdots d_k$,其中$d_0, d_1, \cdots d_k$可以为$\varepsilon$。
因此,我们可以换一个思路。首先,利用kmp算法我们可以求得子串$d_i, i \in [0, k]$在源串$s$上的匹配位置,称之为end-point。
则对通配符分情况讨论:
(1) ?:仅匹配一个字符,那么d_k匹配的有效的end-point的下一个位置仍然可以匹配;
(2) *:可以匹配任意个字符,那么d_k首次匹配的end-point的后续位置都可以匹配。
注意,这里的有效有特殊含义,有效不仅要保证这次的子串$d_i$匹配end-point,同时一定要满足上一次的位置$end-point - |d_i|$同样是可以匹配的。
因此,算法的框架就变成了:
(1) 对模式串进行分割,分割点为?或*;
(2) 在源串中使用kmp算法搜索子串的end-point并且标记;
(3) 利用前次的匹配标记数组$ep$与kmp的标记$visit$共同确定这次的匹配标记;
(4) 对长度为0的字符串单独讨论;
(5) 对不含通配符的模式串,直接strcmp。
3. 代码
1 /* 3901 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #ifndef ONLINE_JUDGE 45 const int maxn = 100; 46 #else 47 const int maxn = 1e5+5; 48 #endif 49 const int maxm = 13; 50 char s[maxn], d[maxn]; 51 bool ep[maxm][maxn]; 52 bool visit[maxn]; 53 char ss[maxn]; 54 int nxt[maxn], slen, dlen; 55 56 void getnext(char *s, int len) { 57 int i, j; 58 59 nxt[0] = -1; 60 i = 0; 61 j = -1; 62 while (i < len) { 63 if (j==-1 || s[i]==s[j]) { 64 ++i; 65 ++j; 66 nxt[i] = j; 67 } else { 68 j = nxt[j]; 69 } 70 } 71 } 72 73 void findEndPoint(char *ss, int len) { 74 int i = 0, j = 0; 75 76 getnext(ss, len); 77 memset(visit, false, sizeof(visit)); 78 while (i < slen) { 79 if (s[i] == ss[j]) { 80 ++i; 81 ++j; 82 } else { 83 j = nxt[j]; 84 if (j == -1) { 85 j = 0; 86 ++i; 87 } 88 } 89 if (j == len) { 90 visit[i] = true; 91 } 92 } 93 } 94 95 void solve() { 96 slen = strlen(s); 97 dlen = strlen(d); 98 int gid = 0; 99 int i = 0, l = 0; 100 101 { 102 // fast check 103 bool flag = true; 104 rep(k, 0, dlen) { 105 if (d[k]=='?' || d[k]=='*') { 106 flag = false; 107 break; 108 } 109 } 110 111 if (flag) { 112 if (strcmp(s,d)==0) 113 puts("YES"); 114 else 115 puts("NO"); 116 return ; 117 } 118 } 119 120 memset(ep, false, sizeof(ep)); 121 ep[gid++][0] = true; 122 while (i < dlen) { 123 if (islower(d[i])) { 124 ss[l++] = d[i++]; 125 continue; 126 } 127 128 ss[l] = '\0'; 129 if (d[i]=='?') { 130 if (l == 0) { 131 rep(i, 0, slen+1) 132 ep[gid][i+1] = ep[gid-1][i]; 133 } else { 134 findEndPoint(ss, l); 135 rep(i, 0, slen+1) { 136 if (ep[gid-1][i] && visit[i+l]) { 137 ep[gid][i+l+1] = true; 138 } 139 } 140 } 141 } else if (d[i]=='*') { 142 if (l == 0) { 143 int fir = slen+1; 144 rep(i, 0, slen+1) { 145 if (ep[gid-1][i]) { 146 fir = i; 147 break; 148 } 149 } 150 151 rep(i, fir, slen+1) 152 ep[gid][i] = true; 153 } else { 154 findEndPoint(ss, l); 155 int fir = slen + 1; 156 rep(i, 0, slen+1) { 157 if (ep[gid-1][i] && visit[i+l]) { 158 fir = i + l; 159 break; 160 } 161 } 162 163 rep(i, fir, slen+1) 164 ep[gid][i] = true; 165 } 166 } 167 168 l = 0; 169 ++gid; 170 ++i; 171 } 172 173 if (l > 0) { 174 ss[l] = '\0'; 175 findEndPoint(ss, l); 176 rep(i, 0, slen+1) { 177 if (ep[gid-1][i] && visit[i+l]) { 178 ep[gid][i+l] = true; 179 } 180 } 181 ++gid; 182 } 183 184 if (ep[gid-1][slen]) 185 puts("YES"); 186 else 187 puts("NO"); 188 } 189 190 int main() { 191 ios::sync_with_stdio(false); 192 #ifndef ONLINE_JUDGE 193 freopen("data.in", "r", stdin); 194 freopen("data.out", "w", stdout); 195 #endif 196 197 while (scanf("%s", s)!=EOF) { 198 scanf("%s", d); 199 solve(); 200 } 201 202 #ifndef ONLINE_JUDGE 203 printf("time = %d.\n", (int)clock()); 204 #endif 205 206 return 0; 207 }