您的位置:首页 > 其它

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");

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: