AC自动机通配符匹配

原文链接:http://blog.csdn.net/waitfor_/article/details/18563709


计算机软件)技术中,通配符可用于代替字符。 通常地,星号“*”匹配0个或以上的字符,问号“?”匹配1个字符。(wiki百科)

今天做Leetcode上的一道题时不会做,网上查到了这么一种做法,当年打比赛的时候都没有碰到过。。。。

Leetcode Wildcard Matching

递归做法TLE

  1. class Solution {  
  2. public:  
  3.     bool isMatch(const char *s, const char *p) {  
  4.         char cs = *s;  
  5.         char cp = *p;  
  6.         if(cp == '\0') {  
  7.             return cs == cp;  
  8.         } else if (cp == '?') {  
  9.             if (cs == '\0'return false;  
  10.             return isMatch(s + 1,p + 1);  
  11.         } else if (cp == '*') {  
  12.             const char *st = s;  
  13.             while(cp == '*'){  
  14.                 p++;  
  15.                 cp = *p;  
  16.             }  
  17.             for(; *st != '\0'; ++st) {  
  18.                 if (isMatch(st, p)) return true;  
  19.             }  
  20.             return isMatch(st,p);  
  21.         } else if (cp != cs)  
  22.             return false;  
  23.         return isMatch(s + 1,p + 1);  
  24.     }  
  25. };  

非递归改改AC

  1. class Solution {  
  2. public:  
  3.     bool isMatch(const char *s, const char *p) {    
  4.         // Start typing your C/C++ solution below    
  5.         // DO NOT write int main() function    
  6.              
  7.         const char* star=NULL;    
  8.         const char* ss=s;     
  9.         while (*s){    
  10.             if ((*p=='?')||(*p==*s)){s++;p++;continue;}    
  11.             if (*p=='*'){star=p++; ss=s;continue;}  //star可以更新,使用贪心法  
  12.             if (star){ p = star+1; s=++ss;continue;}  
  13.             return false;    
  14.         }    
  15.         while (*p=='*'){p++;}    
  16.         return !*p;    
  17.     }    
  18.   
  19. };  
这段代码我参考的http://blog.csdn.net/doc_sgl/article/details/12721187,代码短小精悍,还是知道仔细体会。



HDU 3901
关于AC自动机通配符匹配的相关知识请看点击打开链接

  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<vector>  
  4. using namespace std;  
  5. #define N 100005  
  6. #define B 26  
  7.   
  8. int tree[N][B],size;  
  9. vector<int> key[N];  
  10. int cnt[N],tcnt;  
  11. void build(char str[]){  
  12.     size=tcnt=0;  
  13.     memset(tree[0],0,sizeof(tree[0]));  
  14.     key[0].clear();  
  15.   
  16.     int node=0;  
  17.     for(int i=0;!i||str[i-1];i++){  
  18.         if(str[i]=='?'||str[i]==0){  
  19.             if(node){  
  20.                 key[node].push_back(i-1);  
  21.                 node=0; tcnt++;  
  22.             }  
  23.             continue;  
  24.         }else{  
  25.             int c=str[i]-'a';  
  26.             if(!tree[node][c]){  
  27.                 tree[node][c]=++size;  
  28.                 memset(tree[size],0,sizeof(tree[size]));  
  29.                 key[size].clear();  
  30.             }  
  31.             node=tree[node][c];  
  32.         }  
  33.     }  
  34. }  
  35.   
  36. int que[N];  
  37. int fail[N];  
  38. void getfail(){  
  39.     int *s=que,*e=que;  
  40.     for(int i=0;i<B;i++){  
  41.         if(tree[0][i]){  
  42.             fail[tree[0][i]]=0;  
  43.             *e++=tree[0][i];  
  44.         }  
  45.     }  
  46.     while(s!=e){  
  47.         int p=*s++;  
  48.         for(int i=0;i<B;i++){  
  49.             if(tree[p][i]){  
  50.                 int v=tree[p][i];  
  51.                 *e++=v;  
  52.                 fail[v]=tree[fail[p]][i];  
  53.                 if(key[fail[v]].size()){  
  54.                     key[v].insert(key[v].end(),  
  55.                             key[fail[v]].begin(),key[fail[v]].end());  
  56.                 }  
  57.             }else{  
  58.                 tree[p][i]=tree[fail[p]][i];  
  59.             }  
  60.         }  
  61.     }  
  62. }  
  63.   
  64. int find(char str[]){  
  65.     if(tcnt==0) return 0;  
  66.     int node=0;  
  67.     for(int i=0;str[i];i++){  
  68.         node=tree[node][str[i]-'a'];  
  69.         cnt[i] = 0;   
  70.         for(int j=0;j<key[node].size();j++){  
  71.             if(i>=key[node][j]){  
  72.                 cnt[i-key[node][j]]++;  
  73.                 if(cnt[i-key[node][j]]==tcnt) return i-key[node][j];  
  74.             }  
  75.         }  
  76.     }  
  77.     return -1;  
  78. }  
  79.   
  80. char tmp[N];  
  81. char src[N];  
  82. char wild[N];  
  83. bool match(int ls, int lp){  
  84.     int tl=0;  
  85.     for(int i=0;i<lp;i++) if(wild[i]!='*') tl++;   
  86.     if(tl>ls) return false;  
  87.   
  88.     int s=-1;  
  89.     for(int i=0;i==0||src[i-1];i++){   //如果最左不是*需要从头开始匹配到第一个*  
  90.         if((src[i]!=0&&wild[i]=='?')||src[i]==wild[i]) continue;  
  91.         if(wild[i]=='*') s=i+1;  
  92.         else return false;  
  93.         break;   
  94.     }  
  95.     if(s==-1) return true;   
  96.       
  97.     for(int i=ls-1,j=lp-1;;i--,j--){   //如果最右不是*需要从结尾开始倒着匹配到倒数第一个*  
  98.         if(i==-1&&j==-1) break;  
  99.         if(i==-1){  
  100.             if(wild[j]!='*'return false;   
  101.             break;  
  102.         }  
  103.         if(j==-1) return false;   
  104.         if(src[i]==wild[j]||wild[j]=='?'){  
  105.             src[ls=i] = wild[j] = 0;  
  106.         } else if(wild[j]=='*'break;  
  107.         else return false;  
  108.     }  
  109.   
  110.     int ts=s-1;  
  111.     for(int i=1;i<lp-tl;i++){       //剩下的部分为*......*将其中每个**中间部分用AC自动机匹配即可  
  112.         if(wild[s]=='*'){s++;continue;}  
  113.         int len = 0;  
  114.         for(;wild[s]!='*'&&wild[s];s++){  
  115.             tmp[len]=wild[s];  
  116.             tmp[++len]=0;  
  117.         }  
  118.         s++;  
  119.         build(tmp);  
  120.         getfail();    //这两步构造AC自动机  
  121.         int pos=find(src+ts);   //寻找最左边匹配位置  
  122.         if(pos==-1) return false;   
  123.         else{  
  124.             ts+=pos+len;  
  125.             if(ts>ls) return false;   
  126.         }  
  127.     }  
  128.     return true;   
  129. }   
  130.   
  131. int main(){  
  132.     while(~scanf("%s", src)){  
  133.         scanf("%s", wild);  
  134.         puts(match(strlen(src), strlen(wild))?"YES":"NO");   
  135.     }  
  136. }  

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: AC自动机并没有直接使用KMP匹配算法,但是AC自动机的核心思想可以说是在KMP算法的基础上演化而来的。KMP算法的思想是通过预处理模式串,构建一个状态转移表,然后在匹配时利用状态转移表跳过匹配失败的前缀,从而实现快速匹配AC自动机的思想也是类似的,在预处理模式串的基础上,构建一个有限状态机,然后在匹配文本串的过程中,根据当前字符和状态机的状态转移函数,快速地转移到下一个状态,从而实现快速匹配。因此,可以说AC自动机是KMP算法的一种扩展和升级,它在字符串匹配中具有更加高效和实用的特性。 ### 回答2: AC自动机并没有直接运用KMP匹配算法,但可以说AC自动机是在KMP算法的基础上进行了改进和优化。 KMP(Knuth-Morris-Pratt)算法是一种经典的模式匹配算法,用于在一个主串中查找一个模式串的出现位置。而AC自动机是用于多模式匹配的算法,可以在一个主串中同时查找多个模式串的出现位置。因此,AC自动机是在KMP算法的基础上进行了扩展和改进。 AC自动机的核心思想是构建一个有限状态自动机,在匹配过程中通过状态的转移来优化匹配效率。它利用了KMP算法中的失配函数的思想,但在实现细节和应用场景上有所不同。 AC自动机通过对所有模式串进行预处理和建立状态转移表,可以在O(n+m)的时间复杂度内完成多模式匹配,其中n是主串的长度,m是模式串的平均长度。而KMP算法仅能实现单模式匹配,时间复杂度为O(n+m)。这说明AC自动机在处理多模式匹配问题上的效率更高。 因此,尽管AC自动机没有直接运用KMP算法,但它是在KMP算法的基础上发展起来的一种更高效的多模式匹配算法。 ### 回答3: AC 自动机并没有直接运用 KMP 匹配算法,但是它的构造和搜索过程中使用了类似的思想。 KMP 算法是一种用于字符串匹配的算法,通过预处理模式串来避免不必要的回退,以提高效率。它构建了一个匹配状态机,通过状态转移表来指导搜索过程。 AC 自动机是在多模式串匹配问题上的一种高效算法。它的核心思想是将所有模式串构建成一棵 Trie 树,并通过添加失败指针(failure link)来实现状态转移。这样,在搜索过程中,每次匹配失败时,不仅会跳转到 Trie 树中的下一个状态,还会根据失败指针跳转到一个更为合适的位置,避免了不必要的回退。 虽然 AC 自动机的构造和搜索过程中使用了和 KMP 算法相似的思想,但它们的应用场景和具体实现方法略有不同。AC 自动机主要用于在一个字符串中同时查找多个模式串的出现位置,而 KMP 算法则是以单个模式串作为输入,找到它在目标字符串中的匹配位置。 综上所述,AC 自动机并没有直接使用 KMP 算法,但在构造和搜索过程中使用了类似的思想,更加高效地解决了多模式串匹配问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值