KMPnext数组自看

Posted wtsruvf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMPnext数组自看相关的知识,希望对你有一定的参考价值。

emm。。。无数次再看kmp了 因为一直没做相关的题。。看了就忘看了就忘。。emm。。

next[i]表示去掉第i个元素后,自已的前缀和后缀匹配的最大长度

字符串    a b a b a b z a b a b a b a
next    0 0 0 1 2 3 4 0 1 2 3 4 5 6 0

前缀和后缀是啥意思呢

abababz 前缀有 a ab aba abab ababa ababab 不算最后一个
      后缀有 z bz abz babz ababz bababz 不算第一个
void getNext()
{
    int j, k;
    j = 0; k = -1; next[0] = -1;
    while(j < tlen)
        if(k == -1 || T[j] == T[k])
            next[++j] = ++k;
        else
            k = next[k];

}

根据代码一个个匹配就好了

关键在于next的回溯  为什么要这样回溯

我们再看 字符串  a b a b a b z a b a b a b a

每一个最长长度有两种来源  1、如果当前字符匹配 则由上一个最长长度加一    2、如果不匹配 则看次长长度的下一个字符是否与当前字符匹配。。不匹配就看次次长长度。。以此类推

为什么呢。。。因为我们想要得到到当前位置的最长匹配长度。。

那为什么k = next[k]就能到次长长度的位置呢。。 

我们就看上边那个个字符串  z的下标为6  next[6] = 4表示 去掉位置6的字符后所能匹配的最大长度

那么 这个长度4是由上一个位置推出来的

那么上一个位置是不是就是当前位置的次长长度

既然是上一个位置 为什么 不是k = j - 1而是k = next[k]呢

因为j代表后缀的位置 而k是前缀的位置  因为是找一个次大的前缀来匹配当前后缀

而next[k]是除去k之后的最大匹配长度

其实意思很好懂。。。。记得平行吗。。a//b  b//c  a//c

next[k]与k位置匹配为最大长度

next[j] = k与j位置匹配为最大长度

那next[k]不就是能和j匹配的次大长度吗。。。

匹配就和人情世故一样。。。能通融一下通融一下。。。大的不行那就次大。。次大不行。。。那就次次大。。嗯。。就是这样。。kmp就是遵循了这个法则。。是的。。

 

bin神kmp模板

 

/*
pku3461(Oulipo), hdu1711(Number Sequence)
这个模板 字符串是从0开始的
Next数组是从1开始的


*/
#include <iostream>
#include <cstring>
using namespace std;

const int N = 1000002;
int next[N];
char S[N], T[N];
int slen, tlen;

void getNext()
{
    int j, k;
    j = 0; k = -1; next[0] = -1;
    while(j < tlen)
        if(k == -1 || T[j] == T[k])
            next[++j] = ++k;
        else
            k = next[k];

}
/*
返回模式串T在主串S中首次出现的位置
返回的位置是从0开始的。
*/
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;
    else
        return -1;
}
/*
返回模式串在主串S中出现的次数
*/
int KMP_Count()
{
    int ans = 0;
    int i, j = 0;

    if(slen == 1 && tlen == 1)
    {
        if(S[0] == T[0])
            return 1;
        else
            return 0;
    }
    getNext();
    for(i = 0; i < slen; i++)
    {
        while(j > 0 && S[i] != T[j])
            j = next[j];
        if(S[i] == T[j])
            j++;
        if(j == tlen)
        {
            ans++;
            j = next[j];
        }
    }
    return ans;
}
int main()
{
    
    int TT;
    int i, cc;
    cin>>TT;
    while(TT--)
    {
        cin>>S>>T;
        slen = strlen(S);
        tlen = strlen(T);
        cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()<<endl;
        cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
    }
    return 0;
}
/*
test case
aaaaaa a
abcd d
aabaa b
*/

 







以上是关于KMPnext数组自看的主要内容,如果未能解决你的问题,请参考以下文章

KMPnext数组循环节理解 HDU1358

刚性微分方程与非刚性的大概区分(自看,求指点)

KMP算法的代码实现

自看高清图one笔记自动更新投机取巧是啥意思

2021HDU多校10 - 7084 Pty loves string(KMPnext树+主席树+dfs序)

VSCode自定义代码片段—— 数组的响应式方法