KMP学习总结

初学,理解可能不是那么准确~~
Next数组的含义:next[i]表示第0个元素到第i个元素组成的字符串的最大前缀后缀。Next[0]=0显然。
所以KMP的原理就是
这里写图片描述
通过找出每一阶段最大的相等的前缀后缀,那么匹配到某个字符失配时就可以从前缀的下一个字母开始匹配,而不用再回退匹配。使复杂度降从O(m^n)到O(m+n)。
最重要的就是求next数组,而且next数组在很多题都有应用,不止KMP。
而得到next数组的原理如下:
这里写图片描述
(画风就是这么洒脱,没办法~~~)
如图,如果比较到q,如果q点元素和q点元素相等,那么直接S1的长度加1就是next[q]了,即next[q]=next[q-1]+1。
但是如果不等,就要在S1中找到一个短一点的字符串,如棕色的那段,那样,因为黄色的那段S2和S1是相等的,那么在S1中找到的最长前缀后缀也和S2的后缀相等,这时,如果A点那里和q相等,那么next[q]就是棕色的那段长度+1喽~如果不相等,再向前减,对,这个过程就是代码里那里【k=next[k];】。如果到紫色的那里B和q相同,那么next[q]为紫色的长度+1.如果一直不相等,只能是0喽~
代码如下(代码原网址链接):

void makeNext(const char P[],int next[])
{
    int q,k;//q:模版字符串下标;k:最大前后缀长度
    int m = strlen(P);//模版字符串长度
    next[0] = 0;//模版字符串的第一个字符的最大前后缀长度为0
    for (q = 1,k = 0; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
    {
        while(k > 0 && P[q] != P[k])//递归的求出P[0]•••P[q]的最大的相同的前后缀长度k
            k = next[k-1];          
        if (P[q] == P[k])//如果相等,那么最大相同前后缀长度加1
        {
            k++;
        }
        next[q] = k;
    }
}

但很时候next数组的意义是:next[i]表示第0个元素到第i-1个元素组成的字符串的前缀后缀,也就是如果把上面讨论的数组定义为nexta的话,那么nexta[i]=next[i+1] , 即nexta[0]=next[1]……nexta[n-2]=next[n-1],并定义next[0]=-1。
代码如下:

void GetNext()
{
    //这个代码的原理和上差不多,就是改的短了些
    int j = 0, k = -1;
    Next[0] = -1;
    while (j <= slen)
    {
        if (k == -1 || T[j] == T[k])
        {
            Next[++j] = ++k;
        }
        else
            k = Next[k];
    }
}

int KMP_Index()
{
    int i = 0, j = 0;
    GetNext();
    while (i < slen && j < tlen)
    {
        if (j == -1 || S[i] == T[j])
        {
            i++;
            j++;
        }
        else
            j = Next[j];
    }
    if (j == tlen)
        return i - tlen;
    return -1;
}

也可以求一个字串出现的次数,代码稍作改动即可:

int KMP_Count()
{
    int ans = 0;
    int i = 0, j = 0;
    GetNext();
    while (i != slen && j != tlen)
    {
        if (S[i] == T[j] || j == -1)
            ++i, ++j;   //第一次发现还可以这样写~
        else
            j = Next[j];
        if (j == tlen)
        {
            ++ans;
            j = Next[j];
        }
    }
    return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值