KMP 和 扩展KMP

本文深入解析了KMP算法的原理与实现,包括基本的KMP算法用于字符串匹配,以及扩展KMP算法用于求解字符串与每个后缀的最长公共前缀。通过详细的代码示例,展示了如何构造next数组和extend数组,实现高效字符串搜索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

KMP:在主串S中找子串T的位置KMP算法的时间复杂度O(|S|+|T|)。

#define maxn 1000
char s[maxn],t[maxn];//s为主串,t为子串
int net[maxn],l1,l2;//l1为主串长度,l2为子串长度
void get_next() {
    int i=0,j=-1;
    net[0]=-1;
    while(i<l2) {
        if (j==-1 ||t[i]==t[j])
        {
            ++i,++j;
            if (t[i]!=t[j]) net[i]=j; //优化next数组
            else net[i]=net[j];
        }
        else j=net[j];
    }
    /*for (i=0;i<l2;i++)
        printf("next[%d]=%d\n",i,next[i]);  */
}
//返回子串在主串第pos个字符之后的位置
//若不存在则返回0
int KMP(int pos)
{
    int i=pos,j=0;
    get_next();       //核心部分
    while(i<l1&&j<l2) {
        if (j==-1||s[i]==t[j]) i++,j++;
        else j=net[j];
    }
    if (j==l2) return i-l2;
    else return 0;
}
1

 

void getNext() {
    Next[1] = 0;
    for (int i = 2, j = 0; i <= n; i++) {
        while(j > 0 && a[i] != a[j+1]) j = Next[j];
        if (a[i] == a[j+1]) j++;
        Next[i] = j;
    } 
}
void KMP() {
    for (int i = 1, j = 0; i <= m; i++) {
        while(j > 0 && (j == n || b[i] != a[j+1])) 
            j = Next[j]; 
        if (b[i] == a[j+1]) j++;
        f[i] = j;
        // if (f[i] == n) 此时是A在B中的某一次出现
    }
}
2(来着算法竞赛进阶指南)

 

 

扩展KMP: 

给定串S,和串T,设S的长度为n,T的长度为m,求T与S的每一个后缀(包括S)的最长公共前缀。复杂度为O(n+m)。

设extend数组,extend[i]表示T与S[i,n-1]的最长公共前缀,要求出所有extend[i](0<=i<n)。

 

注意到,如果有一个位置extend[i]=m,则表示T在S中出现,而且是在位置i出现,这就是标准的KMP问题,所以说拓展kmp是对KMP算法的扩展,所以一般将它称为扩展KMP算法。

详细过程参考博客: https://blog.youkuaiyun.com/qq_40160605/article/details/80407554

          https://blog.youkuaiyun.com/dyx404514/article/details/41831947

const int K=1000005;
int nt[K],extand[K];
char S[K];
void Getnext(char *T,int *next)
{
    int len=strlen(T),a=0;
    next[0]=len;
    while(a<len-1 && T[a]==T[a+1]) a++;
    next[1]=a;
    a=1;
    for(int k=2; k<len; k++)
    {
        int p=a+next[a]-1,L=next[k-a];
        if( (k-1)+L >= p)
        {
            int j = (p-k+1)>0 ? (p-k+1) : 0;
            while(k+j<len && T[k+j]==T[j]) j++;
            next[k]=j;
            a=k;
        }
        else next[k]=L;
    }
}
void GetExtand(char *S,char *T,int *next)
{
    Getnext(T,next);
    int slen=strlen(S),tlen=strlen(T),a=0;
    int MinLen = slen < tlen ? slen : tlen;
    while(a<MinLen && S[a]==T[a]) a++;
    extand[0]=a;
    a=0;
    for(int k=1; k<slen; k++)
    {
        int p=a+extand[a]-1, L=next[k-a];
        if( (k-1)+L >= p)
        {
            int j= (p-k+1) > 0 ? (p-k+1) : 0;
            while(k+j<slen && j<tlen && S[k+j]==T[j]) j++;
            extand[k]=j;
            a=k;
        }
        else extand[k]=L;
    }
}
int main()
{
    while(scanf("%s%s",S,T)==2)
    {
        GetExtand(S,T,nt); 
        for(int i=0; i<strlen(T); i++)
            printf("%d ",nt[i]);
        puts("");
        for(int i=0; i<strlen(S); i++)
            printf("%d ",extand[i]);
        puts("");
    }
    return 0;
}
扩展KMP

 

转载于:https://www.cnblogs.com/l999q/p/11304900.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值