【HDOJ】3901 Wildcard
2016-03-29 23:10
225 查看
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. 代码
有两个长度为$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. 代码
/* 3901 */ #include <iostream> #include <sstream> #include <string> #include <map> #include <queue> #include <set> #include <stack> #include <vector> #include <deque> #include <bitset> #include <algorithm> #include <cstdio> #include <cmath> #include <ctime> #include <cstring> #include <climits> #include <cctype> #include <cassert> #include <functional> #include <iterator> #include <iomanip> using namespace std; //#pragma comment(linker,"/STACK:102400000,1024000") #define sti set<int> #define stpii set<pair<int, int> > #define mpii map<int,int> #define vi vector<int> #define pii pair<int,int> #define vpii vector<pair<int,int> > #define rep(i, a, n) for (int i=a;i<n;++i) #define per(i, a, n) for (int i=n-1;i>=a;--i) #define clr clear #define pb push_back #define mp make_pair #define fir first #define sec second #define all(x) (x).begin(),(x).end() #define SZ(x) ((int)(x).size()) #define lson l, mid, rt<<1 #define rson mid+1, r, rt<<1|1 #ifndef ONLINE_JUDGE const int maxn = 100; #else const int maxn = 1e5+5; #endif const int maxm = 13; char s[maxn], d[maxn]; bool ep[maxm][maxn]; bool visit[maxn]; char ss[maxn]; int nxt[maxn], slen, dlen; void getnext(char *s, int len) { int i, j; nxt[0] = -1; i = 0; j = -1; while (i < len) { if (j==-1 || s[i]==s[j]) { ++i; ++j; nxt[i] = j; } else { j = nxt[j]; } } } void findEndPoint(char *ss, int len) { int i = 0, j = 0; getnext(ss, len); memset(visit, false, sizeof(visit)); while (i < slen) { if (s[i] == ss[j]) { ++i; ++j; } else { j = nxt[j]; if (j == -1) { j = 0; ++i; } } if (j == len) { visit[i] = true; } } } void solve() { slen = strlen(s); dlen = strlen(d); int gid = 0; int i = 0, l = 0; { // fast check bool flag = true; rep(k, 0, dlen) { if (d[k]=='?' || d[k]=='*') { flag = false; break; } } if (flag) { if (strcmp(s,d)==0) puts("YES"); else puts("NO"); return ; } } memset(ep, false, sizeof(ep)); ep[gid++][0] = true; while (i < dlen) { if (islower(d[i])) { ss[l++] = d[i++]; continue; } ss[l] = '\0'; if (d[i]=='?') { if (l == 0) { rep(i, 0, slen+1) ep[gid][i+1] = ep[gid-1][i]; } else { findEndPoint(ss, l); rep(i, 0, slen+1) { if (ep[gid-1][i] && visit[i+l]) { ep[gid][i+l+1] = true; } } } } else if (d[i]=='*') { if (l == 0) { int fir = slen+1; rep(i, 0, slen+1) { if (ep[gid-1][i]) { fir = i; break; } } rep(i, fir, slen+1) ep[gid][i] = true; } else { findEndPoint(ss, l); int fir = slen + 1; rep(i, 0, slen+1) { if (ep[gid-1][i] && visit[i+l]) { fir = i + l; break; } } rep(i, fir, slen+1) ep[gid][i] = true; } } l = 0; ++gid; ++i; } if (l > 0) { ss[l] = '\0'; findEndPoint(ss, l); rep(i, 0, slen+1) { if (ep[gid-1][i] && visit[i+l]) { ep[gid][i+l] = true; } } ++gid; } if (ep[gid-1][slen]) puts("YES"); else puts("NO"); } int main() { ios::sync_with_stdio(false); #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); freopen("data.out", "w", stdout); #endif while (scanf("%s", s)!=EOF) { scanf("%s", d); solve(); } #ifndef ONLINE_JUDGE printf("time = %d.\n", (int)clock()); #endif return 0; }
相关文章推荐
- linux centos 7 下安装sublime
- CodeSnippets
- JHotDraw应用程序框架
- QT 简单编写贪吃蛇
- java 日期时间总结
- 大芝麻 APP
- XV6操作系统 学习笔记(源代码共9100行)
- c++第二次实验项目一
- Linux Shell 03 条件测试
- getview里面的viewholde不能加final解决方法
- 206年3月16日作业。
- springmvc概述及框架原理
- 兼容问题汇总
- KMP算法研究(一)
- 【spring基础】spring声明式事务详解
- 关于maven环境变量配置
- redis dump.rdb appendonly.aof 文件路径修改
- bzoj 1049 [HAOI2006]数字序列
- 自定义Android图片轮播控件
- iOS之UILabel自适应大小