首页 > 其他 > 详细

扩展kmp模板

时间:2019-08-10 01:09:28      阅读:111      评论:0      收藏:0      [点我收藏+]

 

目的:找出字符串S的所有后缀与字符串T的最长公共前缀,预处理Next[i]。

   S字符串长度为n,T字符串长度为m。

   Next[i],i∈[0,m),表示T的后缀i与T的最长公共前缀。

   extend[i],i∈[0,n),表示T与S[i,n)的最长公共前缀。如果有一个extend[i]=m,则T在S中在i位置出现。

时间复杂度:O(|S|+|T|)

自用模板:

技术分享图片
#include <iostream>
#include <string.h>
using namespace std;
const int maxn=1100;
int Next[maxn],extend[maxn];
void get_Next(char *s)
{
    int n=strlen(s);
    int i,j,k;
    for(j=0;1+j<n&&s[j]==s[1+j];j++);
    Next[1]=j;
    k=1;
    for(i=2;i<n;i++)
    {
        int len=k+Next[k],L=Next[i-k];
        if(L<len-i)
        {
            Next[i]=L;
        }
        else
        {
            for(j=max(0,len-i);i+j<n&&s[j]==s[i+j];j++);
            Next[i]=j;
            k=i;
        }
    }
    Next[0]=n;
}
void ex_kmp(char *T,char *s)
{
    int n=strlen(T),m=strlen(s);
    int i,j,k;
    for(j=0;j<n&&j<m&&T[j]==s[j];j++);
    extend[0]=j;
    k=0;
    for(i=1;i<n;i++)
    {
        int len=k+extend[k],L=Next[i-k];
        if(L<len-i)
        {
            extend[i]=L;
        }
        else
        {
            for(j=max(0,len-i);j<m&&i+j<n&&s[j]==T[i+j];j++);
            extend[i]=j;
            k=i;       
        }
    }
        
}
//定义母串为s,字串为T,s的长度为n,T的长度为m,求T与S的每一个后缀的最长公共前缀
//设extend数组,extend[i]表示T与S[i,n-1]的最长公共前缀,i从0到n-1,如果有一个extend[i]=m,则T在S中在i位置出现。
int main() 
{
    char s[maxn],T[maxn];
    cin>>T>>s;  //找出T的所有后缀与s的最长公共前缀 
    get_Next(s);
    ex_kmp(T,s);
    for(int i=0;i<strlen(T);i++)
    {
        cout<<extend[i]<<" ";
    }
    cout<<endl;
    return 0;
}
View Code

修改模板:

①配合fail数组进行去重

 int len2=len-fail[len-1]-1;如果len%len2!=0则不必去重,再把len赋值给len2即可。如123123123需要去重,12312312则不需要。

 fail数组:设j=fail[i],满足s0...j=sj-i...i到si的最大的j 

len=8 a b b
fail[] -1 0 -1 0 -1 0 1 2

 

 

 

技术分享图片
#include<bits/stdc++.h>
using namespace std;
const int maxn=100050;
void getfail(char *p,int *fail)
{
    int match=-1;
    fail[0]=-1;
    for(int i=1;p[i];i++)
    {
        while(match>=0&&p[match+1]!=p[i])
        {
            match=fail[match];
        }
        if(p[match+1]==p[i])
        match++;
        fail[i]=match; 
    }
}

int main()
{
    char s[maxn];
    int fail[maxn];
    cin>>s;  //对s进行去重,len2是去重后长度 
    getfail(s,fail);
    int len=strlen(s),len2;
    len2=len-fail[len-1]-1;
    if(len%len2!=0)len2=len;
    cout<<len2<<endl;
    return 0;
}
View Code

 

②修改get_Next函数

Next[i]表示Ti...len-1与T的最长公共前缀,做了一个return max的修改

len=9 a a a b a a a a b
Next[] 9 2 1 0 3 4 2 1 0

 

 

 

技术分享图片
int get_Next(char *s)
{
    int n=strlen(s),ans=0;
    int i,j,k;
    for(j=0;1+j<n&&s[j]==s[1+j];j++);
    Next[1]=j;
    k=1;
    for(i=2;i<n;i++)
    {
        int len=k+Next[k],L=Next[i-k];
        if(L<len-i)
        {
            Next[i]=L;
        }
        else
        {
            for(j=max(0,len-i);i+j<n&&s[j]==s[i+j];j++);
            Next[i]=j;
            k=i;
        }
        if(Next[i]>ans)
        ans=Next[i];
    } 
    Next[0]=n;
    return ans;
}
View Code

 

扩展kmp模板

原文:https://www.cnblogs.com/myrtle/p/11330055.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!