zoukankan      html  css  js  c++  java
  • ac自动机

    ac自动机通常用来解决多字符串匹配问题,如从字符串s找字符串t[i](i<=n),如果直接用KMP那么时间复杂度为,而用ac自动机时间复杂度为

    ac自动机可以认为是kmp和trie的结合,因为ac自动机就是在trie的基础上怎加了fail变量,fail指向的是当前字符串的最长后缀的尾节点,

    作用就是在当前匹配失败时,将当前指针转向fail指向的位置,继续匹配,这样就避免了重复匹配,类似于kmp的next数组的作用。

    下面是HDU 2222 Keywords Search模板代码,求得是出现在主串中的子串个数(重复出现算一次)。

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<queue>
     5 #include<algorithm>
     6 using namespace std;
     7 const int N=1e6+5;
     8 const int M=5e5+5;
     9 
    10 int idx;
    11 int trie[M][26],fail[M],cnt[M];
    12 char s[N];
    13 
    14 void init(){
    15     idx=0;
    16     memset(trie,-1,sizeof(trie));
    17     memset(fail,0,sizeof(fail));
    18     memset(cnt,0,sizeof(cnt));
    19 }
    20 
    21 //插入模式串
    22 void Insert(char *s){
    23     int len=strlen(s);
    24     int now=0;
    25     for(int i=0;i<len;i++){
    26         int ch=s[i]-'a';
    27         if(trie[now][ch]==-1)
    28             trie[now][ch]=++idx;
    29         now=trie[now][ch];
    30     }
    31     cnt[now]++;
    32 }
    33 
    34 //获得fail指针
    35 void getfail(){
    36     fail[0]=0;
    37     queue<int>q;
    38     for(int i=0;i<26;i++){
    39         if(trie[0][i]==-1)
    40             trie[0][i]=0;
    41         else{
    42             fail[trie[0][i]]=0;
    43             q.push(trie[0][i]);
    44         }
    45     }
    46     while(!q.empty()){
    47         int u=q.front();
    48         q.pop();
    49         for(int i=0;i<26;i++){
    50             if(trie[u][i]!=-1){
    51                 fail[trie[u][i]]=trie[fail[u]][i];
    52                 q.push(trie[u][i]);
    53             }
    54             else trie[u][i]=trie[fail[u]][i];
    55         }
    56     }
    57 }
    58 
    59 //这里的意思是如果a出现在s中,那么作为a后缀的b肯定也在s中,所以不断找后缀
    60 int get(int u){
    61     int res=0;
    62     while(u){
    63         res+=cnt[u];
    64         cnt[u]=0;
    65         u=fail[u];
    66     }
    67     return res;
    68 }
    69 
    70 //字符串匹配
    71 int match(char *s){
    72     int len=strlen(s),now=0,ans=0;
    73     for(int i=0;i<len;i++){
    74         int ch=s[i]-'a';
    75         now=trie[now][ch];
    76         //if(cnt[now])          注意这里不能判断cnt[now]>0,比如在she中找模式串she、h其中h是sh的的后缀而cnt[节点h]=0。
    77         ans+=get(now);
    78     }
    79     return ans;
    80 }
    81 
    82 int main(){
    83     int t;
    84     scanf("%d",&t);
    85     while(t--){
    86         init();
    87         int n;
    88         scanf("%d",&n);
    89         for(int i=0;i<n;i++){
    90             scanf("%s",s);
    91             Insert(s);
    92         }
    93         scanf("%s",s);
    94         getfail();
    95         printf("%d
    ",match(s));
    96     }
    97     return 0;
    98 }
  • 相关阅读:
    url
    松弛时间
    Linux下为当前用户添加 PYTHONPATH 环境变量
    ElasticSearch集群的安装(windows)
    软件开发安全
    java,判断手机设备跟adb建立连接
    question
    氚云后台代码小栗子,流程表单新增完成反写源单状态
    November Challenge 2020 Division 1
    February Challenge 2021 Division 1 选做
  • 原文地址:https://www.cnblogs.com/fu3638/p/8543968.html
Copyright © 2011-2022 走看看