• 算法笔记--KMP算法 && EXKMP算法


    1.KMP算法

    这个博客写的不错:http://www.cnblogs.com/SYCstudio/p/7194315.html

    模板:

    next数组的求解,那个循环本质就是如果相同前后缀不能加上该位置成就该位置的next数组就一直找相同前后缀的相同前后缀。

    求解前缀数组F(也叫next数组):

    for (int i=1;i<m;i++)
    {
        int j=F[i-1];
        while ((B[j+1]!=B[i])&&(j>=0))
            j=F[j];
        if (B[j+1]==B[i])
            F[i]=j+1;
        else
            F[i]=-1;
    }

    利用F数组寻找匹配,这里我们是每找到一个匹配就输出其开始的位置:

    while (i<n)
    {
        if (A[i]==B[j])
        {
            i++;
            j++;
            if (j==m)
            {
                printf("%d
    ",i-m+1);
                j=F[j-1]+1;
            }
        }
        else
        {
            if (j==0)
                i++;
            else
                j=F[j-1]+1;
        }
    }

    例题1:P3375 【模板】KMP字符串匹配

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define pb push_back
    #define mem(a,b) memset((a),(b),sizeof(a))
    const int N=1e3+5;
    int f[N]={-1};
    char a[N*N];
    char b[N];
    
    int main()
    {
        /*ios::sync_with_stdio(false);
        cin.tie(0);*/
        scanf("%s",a);
        scanf("%s",b);
        int m=strlen(b);
        int n=strlen(a);
        for(int i=1;i<m;i++)
        {
            int j=f[i-1];
            while(b[j+1]!=b[i]&&j>=0)j=f[j];
            if(b[j+1]==b[i])f[i]=j+1;
            else f[i]=-1;
        }
        
        int i=0,j=0;
        while(i<n)
        {
            if(a[i]==b[j])
            {
                i++;
                j++;
                if(j==m)
                {
                    printf("%d
    ",i-m+1); 
                    j=f[j-1]+1;
                }
            }
            else 
            {
                if(j==0)i++;
                else j=f[j-1]+1;
            }
        }
        
        for(int i=0;i<m;i++)
        {
            printf("%d",f[i]+1);
            if(i!=m-1)printf(" ");
            else printf("
    ");
        }
        return 0;
    } 
    View Code

    例题2:HDU 1711 Number Sequence

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define pb push_back
    #define mem(a,b) memset((a),(b),sizeof(a))
    const int N=1e6+5;
    const int M=1e4+5;
    int f[M]={-1};
    int a[N];
    int b[M];
    
    int main()
    {
        /*ios::sync_with_stdio(false);
        cin.tie(0);*/
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=0;i<n;i++)scanf("%d",&a[i]);
            for(int i=0;i<m;i++)scanf("%d",&b[i]);
            
            for(int i=1;i<m;i++)
            {
                int j=f[i-1];
                while(b[j+1]!=b[i]&&j>=0)j=f[j];
                if(b[j+1]==b[i])f[i]=j+1;
                else f[i]=-1;
            }
            
            int i=0,j=0;
            bool flag=true;
            while(i<n)
            {
                if(a[i]==b[j])
                {
                    i++;
                    j++;
                    if(j==m)
                    {
                        printf("%d
    ",i-m+1);
                        flag=false;
                        break;
                    }
                }
                else
                {
                    if(j==0)i++;
                    else j=f[j-1]+1;
                }
            }
            if(flag)printf("-1
    ");
        }
        
        return 0;
    } 
    View Code

    例题3:POJ 2406 Power Strings

    用next数组求解最小循环节。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define ll long long
    #define pb push_back
    #define mem(a,b) memset((a),(b),sizeof(a))
    const int N=1e6+5;
    int f[N]={-1};
    char s[N];
    
    int main()
    {
        /*ios::sync_with_stdio(false);
        cin.tie(0);*/
        while(scanf("%s",s)!=EOF)
        {
            if(s[0]=='.')break;
            int m=strlen(s);
            for(int i=1;i<m;i++)
            {
                int j=f[i-1];
                while(s[j+1]!=s[i]&&j>=0)j=f[j];
                if(s[j+1]==s[i])f[i]=j+1;
                else f[i]=-1;
            }
            
            int t=m-(f[m-1]+1);
            if(m%t)t=m;//如果不整出,那么不存在最小循环节,或者说最小循环节就是字符串本身 
            printf("%d
    ",m/t);
        }
        return 0;
    } 
    View Code

    例题4:POJ 1961 Period

    求每一段的最小循环节。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define ll long long
    #define pb push_back
    #define mem(a,b) memset((a),(b),sizeof(a))
    const int N=1e6+5;
    int f[N]={-1};
    char s[N];
    
    int main()
    {
        /*ios::sync_with_stdio(false);
        cin.tie(0);*/
        int n;
        int c=0;
        while(scanf("%d",&n)!=EOF&&n)
        {
            scanf("%s",s);
            c++;
            printf("Test case #%d
    ",c);
            int m=strlen(s);
            for(int i=1;i<m;i++)
            {
                int j=f[i-1];
                while(s[j+1]!=s[i]&&j>=0)j=f[j];
                if(s[j+1]==s[i])f[i]=j+1;
                else f[i]=-1;
                int t=i-f[i];
                if((i+1)%t==0&&(i+1)/t>1)printf("%d %d
    ",i+1,(i+1)/t); 
            }
            printf("
    "); 
        }
        return 0;
    } 
    View Code

     例题5: 471D - MUH and Cube Walls

    对差值进行匹配

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    
    const int N=2e5+5;
    int F[N]={-1},A[N],B[N];
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,m;
        cin>>n>>m;
        for(int i=0;i<n;i++)cin>>A[i];
        for(int i=n-1;i>=1;i--)A[i]=A[i]-A[i-1];
        A[0]=0;
        for(int i=0;i<m;i++)cin>>B[i];
        for(int i=m-1;i>=1;i--)B[i]=B[i]-B[i-1];
        if(m==1){
            cout<<n<<endl;
            return 0;
        }
        for(int i=1;i<m;i++)B[i-1]=B[i];
        m--;
        for(int i=1;i<m;i++)
        {
                int j=F[i-1];
                while(B[j+1]!=B[i]&&j>=0)j=F[j];
                if(B[j+1]==B[i])F[i]=j+1;
                else F[i]=-1;
        }
        int cnt=0;
        /*for(int i=0;i<n;i++)cout<<A[i]<<' ';
        cout<<endl;
        for(int i=0;i<m;i++)cout<<B[i]<<' ';
        cout<<endl;
        for(int i=0;i<m;i++)cout<<F[i]<<' ';
        cout<<endl;*/
        int i=1,j=0;
        while (i<n)
        {
            if (A[i]==B[j])
            {
                i++;
                j++;
                if (j==m)
                {
                    cnt++;
                    j=F[j-1]+1;
                }
            }
            else
            {
                if (j==0)
                    i++;
                else
                    j=F[j-1]+1;
            }
            //cout<<i<<' '<<j<<endl;
        }
        cout<<cnt<<endl;
        return 0;
    }
    View Code

     2.exkmp算法

    https://blog.csdn.net/dyx404514/article/details/41831947

    模板: 

    const int N = 1e6 + 5;
    int nxt[N], ex[N];
    void GETNEXT(char *str) {
        int i = 0, j, po, len=strlen(str);
        nxt[0] = len;
        while(str[i] == str[i+1] && i+1 < len) i++;
        nxt[1] = i;
        po = 1;
        for(i = 2; i < len; i++) {
            if(nxt[i-po] + i < nxt[po] + po)
            nxt[i] = nxt[i-po];
            else {
                j=nxt[po] + po - i;
                if(j < 0) j = 0;
                while(i + j < len && str[j] == str[j+i])
                j++;
                nxt[i] = j;
                po = i;
            }
        }
    }
    void EXKMP(char *s1,char *s2)
    {
        int i = 0, j, po, len = strlen(s1), l2=strlen(s2);
        GETNEXT(s2);
        while(s1[i] == s2[i] && i < l2 && i < len) i++;
        ex[0] = i;
        po = 0;
        for(i = 1; i < len; i++)
        {
            if(nxt[i-po] + i < ex[po] + po) ex[i]=nxt[i-po];
            else {
                j = ex[po] + po - i;
                if(j < 0) j = 0;
                while(i + j < len && j < l2 && s1[j+i] == s2[j]) j++;
                ex[i] = j;
                po = i;
            }
        }
    }

    HDU 2594 Simpsons’ Hidden Talents

    代码:

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize(4)
    #include<bits/stdc++.h>
    using namespace std;
    #define y1 y11
    #define fi first
    #define se second
    #define pi acos(-1.0)
    #define LL long long
    //#define mp make_pair
    #define pb push_back
    #define ls rt<<1, l, m
    #define rs rt<<1|1, m+1, r
    #define ULL unsigned LL
    #define pll pair<LL, LL>
    #define pli pair<LL, int>
    #define pii pair<int, int>
    #define piii pair<pii, int>
    #define pdd pair<double, double>
    #define mem(a, b) memset(a, b, sizeof(a))
    #define debug(x) cerr << #x << " = " << x << "
    ";
    #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //head
    
    const int N = 100010;
    int nxt[N], ex[N];
    char s[N], t[N];
    void GETNEXT(char *str) {
        int i = 0, j, po, len = strlen(str);
        nxt[0] = len;
        while(str[i] == str[i+1] && i+1 < len) i++;
        nxt[1] = i;
        po = 1;
        for(i = 2; i < len; i++) {
            if(nxt[i-po] + i < nxt[po] + po)
            nxt[i] = nxt[i-po];
            else {
                j=nxt[po] + po - i;
                if(j < 0) j = 0;
                while(i + j < len && str[j] == str[j+i])
                j++;
                nxt[i] = j;
                po = i;
            }
        }
    }
    void EXKMP(char *s1,char *s2)
    {
        int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
        GETNEXT(s2);
        while(s1[i] == s2[i] && i < l2 && i < len) i++;
        ex[0] = i;
        po = 0;
        for(i = 1; i < len; i++)
        {
            if(nxt[i-po] + i < ex[po] + po) ex[i]=nxt[i-po];
            else {
                j = ex[po] + po - i;
                if(j < 0) j = 0;
                while(i + j < len && j < l2 && s1[j+i] == s2[j]) j++;
                ex[i] = j;
                po = i;
            }
        }
    }
    int main() {
        while(~scanf("%s", &s)) {
            scanf("%s", &t);
            EXKMP(t, s);
            int len = strlen(t), res = 0;
            for (int i = 0; i < len; ++i) {
                if(ex[i]+i == len) {
                    res = ex[i];
                    break;
                }
            }
            for (int i = 0; i < res; ++i) putchar(s[i]);
            if(res)putchar(' ');
            printf("%d
    ", res);
        }
        return 0;
    }
    View Code

    FFT求带通配符的字符串匹配

    void FFT_match(char *s1,char *s2,int m,int n)
    {
        reverse(ss1,ss1+m);
        for(int i=0;i<m;i++) A[i]=(s1[i]!='*')?(s1[i]-'a'+1):0;
        for(int i=0;i<n;i++) B[i]=(s2[i]!='*')?(s2[i]-'a'+1):0;
    
        for(int i=0;i<len;i++) a[i]=Comp(A[i]*A[i]*A[i],0),b[i]=Comp(B[i],0);
        FFT(a,len,1);FFT(b,len,1);
        for(int i=0;i<len;i++) P[i]=P[i]+a[i]*b[i];
    
        for(int i=0;i<len;i++) a[i]=Comp(A[i],0),b[i]=Comp(B[i]*B[i]*B[i],0);
        FFT(a,len,1);FFT(b,len,1);
        for(int i=0;i<len;i++) P[i]=P[i]+a[i]*b[i];
    
        for(int i=0;i<len;i++) a[i]=Comp(A[i]*A[i],0),b[i]=Comp(B[i]*B[i],0);
        FFT(a,len,1);FFT(b,len,1);
        for(int i=0;i<len;i++) P[i]=P[i]-a[i]*b[i]*Comp(2,0);
    
        FFT(P,len,-1);
        for(int i=m-1;i<n;i++) if(fabs(P[i].r)<=1e-7) printf("%d ",i-m+2);
    }
  • 相关阅读:
    php中session的运行机制
    Mysql5.5修改字符集
    java中用StringBuffer写文件换行
    DatabaseMetaData 获取mysql表和字段注释
    DatabaseMetaData 获取oracle字段注释
    常用的easyui使用方法
    定位div滚动条
    easyui edatagrid 触发编辑行回掉onEdit
    java 读取类内容给指定的方法追加内容
    JS中文转换(UTF-8),中文乱码解决办法,url传递中文乱码解决
  • 原文地址:https://www.cnblogs.com/widsom/p/7363498.html
Copyright © 2020-2023  润新知