首页 > 其他分享 >KMP

KMP

时间:2022-11-14 18:24:38浏览次数:38  
标签:nxt int fa mp KMP inf

前缀函数nxt[i]表示s[0...i]最长相等的真前缀与真后缀的长度。

i-nxt[i]即为s[0...i]的一个周期。

前缀函数求法,j代表的时长度。

下标从0开始。

    for(int i=1,j=0;i<n;i++){/*j最次也是前一位的nxt,从前一位失配的位置开始匹配,后缀与前缀不等时一直往前跳*/
        while(j&&s[i]!=s[j])j=nxt[j-1];/*不相等时一直跳到前一个下标的nxt,因为这里j是长度*/
        if(s[i]==s[j])j++;/*匹配到相等的前缀和后缀,j为下一位*/
        nxt[i]=j;
    }

下标从1开始。

for(int i=2,j=0;i<=n;i++){
    while(j&&s[i]!=s[j+1])j=nxt[j];
    if(s[i]==s[j+1])j++;
    nxt[i]=j;
}

KMP匹配,text为文本串,s为模式串。

下标从1开始。

for(int i=1,j=0;i<=m;i++){
    while(j&&t[i]!=s[j+1])j=nxt[j];
    if(t[i]==s[j+1])j++;
    if(j==n)j=nxt[j];/*匹配完了一整个串,进行相应处理,之后跳回到nxt继续匹配*/
}

下标从0开始。

for(int i=0,j=0;i<m;i++){
    while(j&&t[i]!=s[j])j=nxt[j-1];
    if(t[i]==s[j])j++;
    if(j==n)j=nxt[j];/*跳回继续匹配*/
}

字符串s由a不断自我拼接而成,已知s,求a的最小长度。可以转化题意为求s的最小长度循环,答案为n-nxt[n].

    cin>>n>>s;
    for(int i=1,j=0;i<n;i++){
        while(j&&s[i]!=s[j])j=nxt[j-1];
        if(s[i]==s[j])j++;
        nxt[i]=j;
    }
    cout<<n-nxt[n-1];

求一个字符串s[1...i]内不可重叠公共前后缀数量。首先通过递推求出可重叠公共前后缀,之后再KMP时,当j>i/2就一直跳j的nxt直到小于i/2,此时累加答案。

        for(int i=2,j=0;i<=n;i++){
            while(j&&s[i]!=s[j+1])j=nxt[j];
            if(s[i]==s[j+1])j++;
            nxt[i]=j;
            num[i]=num[j]+1;
        }
        for(int i=1,j=0;i<=n;i++){
            while(j&&s[i]!=s[j+1])j=nxt[j];
            if(s[i]==s[j+1])j++;
            while(j>i>>1)j=nxt[j];
            (ans*=(num[j]+1))%=mod;
        }

求一个字符串所有前缀的最大周期之和。每次KMP时从i开始跳nxt,可以记忆化,找到最小的nxt之后更新ans。

    for(int i=1,j=0;i<=n;i++){
        j=i;
        while(nxt[j])j=nxt[j];
        if(nxt[i])nxt[i]=j;
        ans+=i-j;
    }

失配树,也是border树,多次询问同一个字符串的两个前缀的最长公共border。为nxt数组建立一棵fail树,相当于只有一个字符串的AC自动机的fail树,询问就是两个点的LCA,但是当两个点有祖先和后代关系时,答案是祖先的父亲,因为border不能包括自身。

inline int LCA(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=20;~i;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
    if(x==y)return fa[x][0];
    for(int i=20;~i;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
    for(int i=2,j=0;i<=n;i++){
        while(j&&s[i]!=s[j+1])j=fa[j][0];
        if(s[i]==s[j+1])j++;
        fa[i][0]=j;
        dep[i]=dep[j]+1;
    }
    for(int j=1;j<=20;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
    int m;
    cin>>m;
    while(m--){
        int x,y;
        cin>>x>>y;
        cout<<LCA(x,y)<<'\n';
    }

给出明文和密文,求密文在明文中可能第一次出现的位置。由于是加密过的,所以只关心距离上一个的单词的距离,第一次出现设为inf,之后进行KMP匹配。但是这样存在问题,文本串中a在整个模式串之前出现过,而模式串却是第一次出现,所以在匹配范围内的a文本串不为inf,模式串为inf,需要判断这种情况,比较文本串中距离上一个数的距离和当前匹配的模式串第几个字符来判断是否还在匹配范围内。

    for(n=1;cin>>s&&s[0]!='$';n++){
        if(!mp[s])a[n]=inf;
        else a[n]=n-mp[s];
        mp[s]=n;
    }
    mp.clear();
    n--;
    for(m=1;cin>>s&&s[0]!='$';m++){
        if(!mp[s])b[m]=inf;
        else b[m]=m-mp[s];
        mp[s]=m;
    }
    m--;
    for(int i=2,j=0;i<=m;i++){
        while(j&&b[i]!=b[j+1])j=nxt[j];
        if(b[i]==b[j+1])j++;
        nxt[i]=j;
    }
    for(int i=1,j=0;i<=n;i++){
        while(j&&(b[j+1]==inf&&a[i]<j+1||b[j+1]!=inf&&a[i]!=b[j+1]))j=nxt[j];
        if(!(b[j+1]==inf&&a[i]<j+1||b[j+1]!=inf&&a[i]!=b[j+1]))j++;
        if(j==m)return cout<<i-m+1,0;
    }

求若干字符串的最长公共子串,字串相同为长度相同且一个串全部加上一个数可以变成另外一个串。首先为每个串做差分,之后枚举第一个串的所有后缀,用这个后缀去和剩下的串进行KMP匹配得到一个公共子串,所有的公共子串取max。

    for(int i=1;i<=n;i++){
        cin>>a[0][i];
        for(int j=0;j<a[0][i];j++)cin>>a[i][j];
        for(int j=0;j<a[0][i];j++)a[i][j]=a[i][j+1]-a[i][j];
        --a[0][i];
    }
    int ans=0;
    for(int i=0;i<a[0][1];i++){
        int k=inf;
        getnext(a[1]+i,a[0][1]-i);
        for(int j=2;j<=n;j++)k=min(KMP(a[j],a[0][j],a[1]+i,a[0][1]-i),k);
        ans=max(ans,k+1);
    }

标签:nxt,int,fa,mp,KMP,inf
From: https://www.cnblogs.com/safeng/p/16889898.html

相关文章

  • KMP
    Java代码importjava.io.*;/***@authorjeffery.ma*@date2022/10/2413:56*/publicclassMain{publicstaticvoidmain(String[]args)throwsIOE......
  • AC 自动机——trie 树与 KMP 算法的结合体
    默认所有字符串的下表从\(1\)开始。梗概与实现如果是单一的模式串和字符串进行匹配,KMP算法自然可以派上用场。但如果有多个模式串呢?对每个模式串都跑一遍KMP?如果有......
  • KMP——字符串匹配的利器
    默认所有字符串的下标从\(1\)开始。\(\text{KMP(Knuth-Morris-Pratt)}\)算法,能够在\(O(|s|+|p|)\)的时间复杂度内求出模式串\(p\)在文本串\(s\)中的出现次数、......
  • KMP算法
    KMP算法是一个字符串匹配算法,或者说是一个子字符串匹配算法算法在字符串str中搜索子串pattern,如果存在,返回这个子串的起始索引,如果不存在,返回-1暴力枚举匹配暴力的字符......
  • 关于KMP的应用几例
    信息竞赛中,KMP大概是字符串方面最经典的算法了。参考了部分代码,KMP的写法大概有两种在原有字符串上进行KMP#include<bits/stdc++.h>usingnamespacestd;constint......
  • kmp板子
    主串a,模式串b,求b在a中出现的位置 #include<iostream>#include<algorithm>#include<cstring>usingnamespacestd;constintN=1e6+4;intla,lb;intf[N],p[N]......
  • 【模板】Z 函数(扩展 KMP)
    postedon2022-08-0823:29:53|under模板|source#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;typedeflonglongLL;intn,......
  • KMP 自动机,孤独的自动机(同时也是CF1721E的题解)
    给定字符串\(s\),以及\(q\)个串\(t_i\),求将\(s\)分别与每个\(t_i\)拼接起来后,最靠右的\(|t_i|\)个前缀的border长度。询问间相互独立。\(|s|\leq10^6,q......
  • KMP算法
    见csdn博主v_JULY_v的详解如下:https://blog.csdn.net/v_JULY_v/article/details/7041827?ops_request_misc=%257B%2522request%255Fid%2522%253A%25221667467393168001806......
  • HDU 1686Oulipo ———————Hash or KMP
    OulipoOulipoTimeLimit:3000/1000MS(Java/Others)    MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):22302    AcceptedSubmission(s):86......