扩展kmp算法讲解

参考文章http://www.cnblogs.com/10jschen/archive/2012/09/03/2668149.html

一.扩展kmp得到的是什么

字符串A,B。B是模式串(子串)。求解A[i ……lenA -1]与B的最长公共前缀,记录在数组ex[i]中

二.算法实现

分为两步,第一步是对B模式串进行处理也是求B[i,Blen - 1]与B的最长公共前缀,用next数组存储,第二部是将A与B进行匹配,其实他们的方法是一样的

我们先对第二步进行分析

首先假设B的nexta[]的值已经全部求出,且i之前全部的ex值也已经求出,再设p为匹配过程中的最大位置,设k为达到最大位置时的起始位置,由此可知p = k + ex[k] - 1

由ex的定义可知:A[k……k + ex[k] -1]   与B[0……ex[k] - 1]相等 显然i > k  所以 A[i……k + ex[k] - 1]  

与 B[i - k……ex[k]-1] 匹配,设L = nexta[i - k],根据nexta的定义有B[0……L-1]  = B[i-k……i - k + L - 1]

只需判断ex[k] - 1(=p - k ) 与 i - k + L - 1那个大

1.i - k + L - 1 < p - k    及 p > i + L - 1,p >= i + L

A[i……p]  与 B[i - k……p-k] 匹配得到A[i……L + i - 1]B[i - k……i - k + L - 1] ,又有B[0……L-1]  = B[i-k……i - k + L - 1]。故A[i……L + i - 1] = B[0……L-1]  可知ex[i] >= L,如果ex[i] > L则A[i……L + i ] = B[0……L] .因为p = k + ex[k] - 1 >= i + L,所以A[i……L + i] = B[i - k……i - k + L],推出B[0……L] = k + ex[k] - 1与next数组定义不符合。所以ex[i] = L

2.i - k + L - 1 >= p - k    及 p <= i + L - 1,p < i + L

A[i……p]  = B[i - k……p-k]

B[0……L-1]  = B[i-k……i - k + L - 1] 所以B[0……p -i]  = B[i-k……p - k]

所以A[i……p]  = B[0……p -i],p是匹配到的最远的地方,需要继续从A[p + 1] 和 B[p - i + 1]开始继续匹配

设j = p - i + 1,则 p  + 1 = i + j。p增加了,所以要更新p和k的值

ps:注意j如果是小于零的就让j = 0,从B的最前端开始匹配

第一步显然和第二步的方法是一样的,注意第一步中都是nexta数组

对于B来说nexta[0]  肯定等于n,然后求出nexta[1]的最远距离,另k = 1,不用对p赋值

对于AB匹配来说,要遍历求出extend[0],遍历应该到两个字符串中长度较短的一个就停止。并另k = 0。

代码如下

//需定义extend 和 nexta
void EKMP(char s[],char t[])//s主串,t模式串
{
    memset(nexta,0,sizeof(nexta));
    memset(extend,0,sizeof(extend));
    int slen = strlen(s),tlen = strlen(t);
    int len = min(slen,tlen);
    nexta[0] = tlen;
    int k;
    for(k = 0;k + 1 < tlen && t[k] == t[k + 1];k ++ )
    {
    }
    nexta[1] = k;
    k = 1;
    int p,L,j;
    for(int i = 2; i < tlen; i ++)
    {
        p = k + nexta[k] - 1, L = nexta[i - k];
        if(i + L <= p)
        {
            nexta[i] = L;
        }
        else
        {
            j = p - i + 1;
            if(j < 0)
                j = 0;
            while(i + j < tlen && t[i + j] == t[j])
            {
                j++;
            }
            nexta[i] = j;
            k = i;
        }
    }
    for(k = 0;k < len && s[k] == t[k];k ++ )
    {
    }
    extend[0] = k;
    k = 0;
    for(int i = 1; i < slen; i ++)
    {
        p = k + extend[k] - 1, L = nexta[i - k];//注意p是加extend
        if(i + L <= p)
        {
            extend[i] = L;
        }
        else
        {
            int j = p - i + 1;
            if(j < 0)
                j = 0;
            while(i + j < slen &&j < tlen && s[i + j] == t[j])
            {
                j++;
            }
            extend[i] = j;
            k = i;
        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值