AC自动机通配符匹配
2015-09-18 15:48
176 查看
原文链接:http://blog.csdn.net/waitfor_/article/details/18563709
在计算机(软件)技术中,通配符可用于代替字符。
通常地,星号“*”匹配0个或以上的字符,问号“?”匹配1个字符。(wiki百科)
今天做Leetcode上的一道题时不会做,网上查到了这么一种做法,当年打比赛的时候都没有碰到过。。。。
Leetcode Wildcard Matching
递归做法TLE
class Solution {
public:
bool isMatch(const char *s, const char *p) {
char cs = *s;
char cp = *p;
if(cp == '\0') {
return cs == cp;
} else if (cp == '?') {
if (cs == '\0') return false;
return isMatch(s + 1,p + 1);
} else if (cp == '*') {
const char *st = s;
while(cp == '*'){
p++;
cp = *p;
}
for(; *st != '\0'; ++st) {
if (isMatch(st, p)) return true;
}
return isMatch(st,p);
} else if (cp != cs)
return false;
return isMatch(s + 1,p + 1);
}
};
非递归改改AC
class Solution {
public:
bool isMatch(const char *s, const char *p) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
const char* star=NULL;
const char* ss=s;
while (*s){
if ((*p=='?')||(*p==*s)){s++;p++;continue;}
if (*p=='*'){star=p++; ss=s;continue;} //star可以更新,使用贪心法
if (star){ p = star+1; s=++ss;continue;}
return false;
}
while (*p=='*'){p++;}
return !*p;
}
};
这段代码我参考的http://blog.csdn.net/doc_sgl/article/details/12721187,代码短小精悍,还是知道仔细体会。
HDU 3901
关于AC自动机通配符匹配的相关知识请看点击打开链接
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define N 100005
#define B 26
int tree
[B],size;
vector<int> key
;
int cnt
,tcnt;
void build(char str[]){
size=tcnt=0;
memset(tree[0],0,sizeof(tree[0]));
key[0].clear();
int node=0;
for(int i=0;!i||str[i-1];i++){
if(str[i]=='?'||str[i]==0){
if(node){
key[node].push_back(i-1);
node=0; tcnt++;
}
continue;
}else{
int c=str[i]-'a';
if(!tree[node][c]){
tree[node][c]=++size;
memset(tree[size],0,sizeof(tree[size]));
key[size].clear();
}
node=tree[node][c];
}
}
}
int que
;
int fail
;
void getfail(){
int *s=que,*e=que;
for(int i=0;i<B;i++){
if(tree[0][i]){
fail[tree[0][i]]=0;
*e++=tree[0][i];
}
}
while(s!=e){
int p=*s++;
for(int i=0;i<B;i++){
if(tree[p][i]){
int v=tree[p][i];
*e++=v;
fail[v]=tree[fail[p]][i];
if(key[fail[v]].size()){
key[v].insert(key[v].end(),
key[fail[v]].begin(),key[fail[v]].end());
}
}else{
tree[p][i]=tree[fail[p]][i];
}
}
}
}
int find(char str[]){
if(tcnt==0) return 0;
int node=0;
for(int i=0;str[i];i++){
node=tree[node][str[i]-'a'];
cnt[i] = 0;
for(int j=0;j<key[node].size();j++){
if(i>=key[node][j]){
cnt[i-key[node][j]]++;
if(cnt[i-key[node][j]]==tcnt) return i-key[node][j];
}
}
}
return -1;
}
char tmp
;
char src
;
char wild
;
bool match(int ls, int lp){
int tl=0;
for(int i=0;i<lp;i++) if(wild[i]!='*') tl++;
if(tl>ls) return false;
int s=-1;
for(int i=0;i==0||src[i-1];i++){ //如果最左不是*需要从头开始匹配到第一个*
if((src[i]!=0&&wild[i]=='?')||src[i]==wild[i]) continue;
if(wild[i]=='*') s=i+1;
else return false;
break;
}
if(s==-1) return true;
for(int i=ls-1,j=lp-1;;i--,j--){ //如果最右不是*需要从结尾开始倒着匹配到倒数第一个*
if(i==-1&&j==-1) break;
if(i==-1){
if(wild[j]!='*') return false;
break;
}
if(j==-1) return false;
if(src[i]==wild[j]||wild[j]=='?'){
src[ls=i] = wild[j] = 0;
} else if(wild[j]=='*') break;
else return false;
}
int ts=s-1;
for(int i=1;i<lp-tl;i++){ //剩下的部分为*......*将其中每个**中间部分用AC自动机匹配即可
if(wild[s]=='*'){s++;continue;}
int len = 0;
for(;wild[s]!='*'&&wild[s];s++){
tmp[len]=wild[s];
tmp[++len]=0;
}
s++;
build(tmp);
getfail(); //这两步构造AC自动机
int pos=find(src+ts); //寻找最左边匹配位置
if(pos==-1) return false;
else{
ts+=pos+len;
if(ts>ls) return false;
}
}
return true;
}
int main(){
while(~scanf("%s", src)){
scanf("%s", wild);
puts(match(strlen(src), strlen(wild))?"YES":"NO");
}
}
在计算机(软件)技术中,通配符可用于代替字符。
通常地,星号“*”匹配0个或以上的字符,问号“?”匹配1个字符。(wiki百科)
今天做Leetcode上的一道题时不会做,网上查到了这么一种做法,当年打比赛的时候都没有碰到过。。。。
Leetcode Wildcard Matching
递归做法TLE
class Solution {
public:
bool isMatch(const char *s, const char *p) {
char cs = *s;
char cp = *p;
if(cp == '\0') {
return cs == cp;
} else if (cp == '?') {
if (cs == '\0') return false;
return isMatch(s + 1,p + 1);
} else if (cp == '*') {
const char *st = s;
while(cp == '*'){
p++;
cp = *p;
}
for(; *st != '\0'; ++st) {
if (isMatch(st, p)) return true;
}
return isMatch(st,p);
} else if (cp != cs)
return false;
return isMatch(s + 1,p + 1);
}
};
非递归改改AC
class Solution {
public:
bool isMatch(const char *s, const char *p) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
const char* star=NULL;
const char* ss=s;
while (*s){
if ((*p=='?')||(*p==*s)){s++;p++;continue;}
if (*p=='*'){star=p++; ss=s;continue;} //star可以更新,使用贪心法
if (star){ p = star+1; s=++ss;continue;}
return false;
}
while (*p=='*'){p++;}
return !*p;
}
};
这段代码我参考的http://blog.csdn.net/doc_sgl/article/details/12721187,代码短小精悍,还是知道仔细体会。
HDU 3901
关于AC自动机通配符匹配的相关知识请看点击打开链接
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define N 100005
#define B 26
int tree
[B],size;
vector<int> key
;
int cnt
,tcnt;
void build(char str[]){
size=tcnt=0;
memset(tree[0],0,sizeof(tree[0]));
key[0].clear();
int node=0;
for(int i=0;!i||str[i-1];i++){
if(str[i]=='?'||str[i]==0){
if(node){
key[node].push_back(i-1);
node=0; tcnt++;
}
continue;
}else{
int c=str[i]-'a';
if(!tree[node][c]){
tree[node][c]=++size;
memset(tree[size],0,sizeof(tree[size]));
key[size].clear();
}
node=tree[node][c];
}
}
}
int que
;
int fail
;
void getfail(){
int *s=que,*e=que;
for(int i=0;i<B;i++){
if(tree[0][i]){
fail[tree[0][i]]=0;
*e++=tree[0][i];
}
}
while(s!=e){
int p=*s++;
for(int i=0;i<B;i++){
if(tree[p][i]){
int v=tree[p][i];
*e++=v;
fail[v]=tree[fail[p]][i];
if(key[fail[v]].size()){
key[v].insert(key[v].end(),
key[fail[v]].begin(),key[fail[v]].end());
}
}else{
tree[p][i]=tree[fail[p]][i];
}
}
}
}
int find(char str[]){
if(tcnt==0) return 0;
int node=0;
for(int i=0;str[i];i++){
node=tree[node][str[i]-'a'];
cnt[i] = 0;
for(int j=0;j<key[node].size();j++){
if(i>=key[node][j]){
cnt[i-key[node][j]]++;
if(cnt[i-key[node][j]]==tcnt) return i-key[node][j];
}
}
}
return -1;
}
char tmp
;
char src
;
char wild
;
bool match(int ls, int lp){
int tl=0;
for(int i=0;i<lp;i++) if(wild[i]!='*') tl++;
if(tl>ls) return false;
int s=-1;
for(int i=0;i==0||src[i-1];i++){ //如果最左不是*需要从头开始匹配到第一个*
if((src[i]!=0&&wild[i]=='?')||src[i]==wild[i]) continue;
if(wild[i]=='*') s=i+1;
else return false;
break;
}
if(s==-1) return true;
for(int i=ls-1,j=lp-1;;i--,j--){ //如果最右不是*需要从结尾开始倒着匹配到倒数第一个*
if(i==-1&&j==-1) break;
if(i==-1){
if(wild[j]!='*') return false;
break;
}
if(j==-1) return false;
if(src[i]==wild[j]||wild[j]=='?'){
src[ls=i] = wild[j] = 0;
} else if(wild[j]=='*') break;
else return false;
}
int ts=s-1;
for(int i=1;i<lp-tl;i++){ //剩下的部分为*......*将其中每个**中间部分用AC自动机匹配即可
if(wild[s]=='*'){s++;continue;}
int len = 0;
for(;wild[s]!='*'&&wild[s];s++){
tmp[len]=wild[s];
tmp[++len]=0;
}
s++;
build(tmp);
getfail(); //这两步构造AC自动机
int pos=find(src+ts); //寻找最左边匹配位置
if(pos==-1) return false;
else{
ts+=pos+len;
if(ts>ls) return false;
}
}
return true;
}
int main(){
while(~scanf("%s", src)){
scanf("%s", wild);
puts(match(strlen(src), strlen(wild))?"YES":"NO");
}
}
相关文章推荐
- 再议GCC编译时的静态库依赖次顺问题
- Activiti工作流(4):编写一个HelloWorld
- Tween(GreenSock)
- NSMutableString
- NSMutableArray 排序
- R中设置图形参数--函数par()…
- [转载]hive的查询注意事项以及优…
- hive大数据倾斜总结
- SAS中常用选项的含义简介
- 黑马程序员_编写程序,打印1到100之内的整数,但数字中包含7的要跳过,例如:17、27、71、72
- 用gbm包来提升决策树能力
- Python 中的 property 属性
- 随机森林 VS Grad…
- hive array、map、stru…
- R主页上的图的代码
- Python教程:[63]操作目录/路径【2…
- 【转载】Python 基础语法(二)…
- SAS hash 树与多维临时数组的比较
- 获取输入字符串的下一个字典序排列
- MySQL Join算法与调优白皮书(三)