算法笔记--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\n",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\n",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("\n");
    }
    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\n",i-m+1);
                    flag=false;
                    break;
                }
            }
            else
            {
                if(j==0)i++;
                else j=f[j-1]+1;
            }
        }
        if(flag)printf("-1\n");
    }
    
    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\n",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\n",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\n",i+1,(i+1)/t); 
        }
        printf("\n"); 
    }
    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 << "\n";
#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\n", 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);
}

 

posted @ 2017-08-15 09:53  Wisdom+.+  阅读(357)  评论(0编辑  收藏  举报