美文网首页DataStructure
KMP中的next数组

KMP中的next数组

作者: 雨落八千里 | 来源:发表于2019-08-06 14:08 被阅读0次

KMP算法首先要构造匹配子串的next数组。假设有两个字符串,一个是待匹配的字符串strText,一个是要查找的匹配子串strKey。现在我们要在strText中去查找是否包含strKey,用i来表示strText遍历到了哪个字符,用j来表示strKey匹配到了哪个字符。假如strText[i]!=strKey[j],那么strKey就要回到nxet[j]字符处。next[j] 中保存的是该失配字符的前一个字符在前面出现过的最近一次失配的字符后面的一个字符的位置
假如字符E失配,那它要返回字符3(D),有什么发现,E到D之间有ABC,D之前也有ABC。再假如字符6(C)失配,它返回字符2(C),发现6字符前有AB,字符2前也有AB。是不是失配前一个字符加上几个字符会等于这个字符的前缀呢!对的,next的数组就是记录j字符的前一个字符串的字符前缀与字符后缀最大相等长度。

next数组的构建


请仔细对比这两个图。
我们发现一个规律:
S[k] == S[j]时,
next[j+1] == next[j] + 1
其实这个是可以证明的:
因为在S[j]之前已经有S[0, k-1] == S[j-k , j-1]
(next[j] == k
这时候现有S[k] == S[j],我们是不是可以得到S[0 , k-1] + S[k] == S[j-k , j-1] + S[j]
即:S[0 , k] == S[j-k , j],即next[j+1] == k + 1 == next[j] + 1
void getnext(int len)
{
    int j=0;
    int k=-1;
    nxt[0]=-1;
    while(j<len)
    {
        if(k==-1||s[j]==s[k])
        {
            j++;
            k++;
            nxt[j]=k;
        }
        else
        {
            k=nxt[k];//窗口
        }
    }
}

哪next数组还有什么用呢?
next数组一直往前走,得到的所有前缀也是当前主串的后缀,当然了,也是当前主串的前缀。


如果到位置 i ,如果有 i%(i-next[i])==0 , 那说明字符串开始循环了,并且循环到 i-1 结束,为什么这样呢?
我们先假设到达位置 i-1 的时候,字符串循环了(到i-1完毕),那么如果到第i个字符的时候,失配了,根据next数组的求法,我们是不是得回溯?
然而回溯的话,由于字符串是循环的了(这个是假定的),next[i] 是不是指向上一个循环节的后面一个字符呢??是的,上一个循环节的末尾是 next[i]-1 ,然后现在循环节的末尾是 i-1 ,然么循环节的长度是多少呢?
所以,我们有 (i - 1) - ( next[i] - 1 ) = i - next[i] 就是循环节的长度(假设循环成立的条件下),但是我们怎么知道这个循环到底成立吗?
现在我们已经假设了 0————i-1 循环了,那么我们就一共有i 个字符了,如果有 i % ( i - next[i] ) == 0,总的字符数刚好是循环节的倍数,那么说明这个循环是成立的。当然,i%i=0,所以还要确保nxet[i]!=0;
  • 周期性字符串⇔ n % (n−next[n])==0 && next[n] != 0,循环节长度是n−next[n]
  • next数组往前跳的步长是一样的,除了最后一次。即i-next[i]

HDU-3746Cyclic Nacklace

将字符串弄成至少两个循环节(保证最后是循环节)至少要添加多少个字符。若本身有至少有两个循环节且最后是循环节结尾就输出0.

#include<bits/stdc++.h>
using namespace std;
const int M=101000;
char s[M];
int nxt[M];
void getnext(int len)
{
    int j=0;
    int k=-1;
    nxt[0]=-1;
    while(j<len)
    {
        if(k==-1||s[j]==s[k])
        {
            k++;
            j++;
            nxt[j]=k;
        }
        else
        {
            k=nxt[k];
        } 
    }
}
int main( )
{
    int t;
    scanf("%d",&t);
    getchar( );
    while(t--)
    {
        scanf("%s",s);
        int len=strlen(s);
        getnext(len);
        if(nxt[len]!=0)
        {
            int k=len-nxt[len];
            if(len%k==0&&len/k>=2)
            {
                printf("0\n");
            }
            else
            {
                printf("%d\n",k-len%k);
            }
            
        }
        else
        {
            printf("%d\n",len);
        }
        
    }
    return 0;
}

HDU-1358Period

输出以每个字符结尾能构成周期

#include<bits/stdc++.h>
using namespace std;
const int M= 1000000;
char s[M];
int nxt[M];
void getnext(int len)
{
    int j=0;
    int k=-1;
    nxt[0]=-1;
    while(j<len)
    {
        if(k==-1||s[j]==s[k])
        {
            j++;
            k++;
            nxt[j]=k;
        }
        else
        {
            k=nxt[k];
        }
    }
}
int main( )
{
    int n;
    int k=0;
    while(~scanf("%d",&n)&&n)
    {
        k++;
        getchar( );
        scanf("%s",s);
        getnext(n);
        printf("Test case #%d\n",k);
        for(int i=1;i<=n;i++)
        {
            if(i%(i-nxt[i])==0&&nxt[i]!=0)
            {
                printf("%d %d\n",i,i/(i-nxt[i]));
            }
        }
        printf("\n");
    }
    return 0;
}

相关文章

  • KMP实现

    kmp next数组 理解

  • KMP算法

    字符串匹配算法之KMP KMP算法最主要的地方是求next数组,next数组保存的是当前失配节点(下标index)...

  • KMP中的next数组

    KMP算法首先要构造匹配子串的数组。假设有两个字符串,一个是待匹配的字符串,一个是要查找的匹配子串。现在我们要在中...

  • 问答|KMP算法学习笔记

    问题 目录KMP是什么,做什么用的KMP算法的高效体现在哪如何KMP算法的next数组KMP的代码KMP的时间复杂...

  • 数据结构与算法14-字符串匹配与KMP

    什么是KMP KMP算法是在字符串匹配算法中比较绕的.主要是需要理解KMP中next数组求解的必要性以及j 的回溯...

  • 字符串匹配问题-KMP算法

    什么是KMP KMP算法是在字符串匹配算法中比较绕的.主要是需要理解KMP中next数组求解的必要性以及j 的回溯...

  • KMP算法的简单实现

    KMP的工作原理 阮一峰的博客讲的非常好点击访问!! KMP的代码实现 动态规划求解NEXT 这里设NEXT数组等...

  • kmp算法

    精华之处:求next数组(自动机) KMP与getNext方法相同,只有next[suffix] = prefix...

  • 字符串KMP+子串的拼接

    KMP(str, target): 使用next数组(位置 i 前面有长度为next[i]的子串和target前面...

  • kmp_algorithm

    tips:kmp算法分两个步骤:1)计算子串的next数组2)匹配子串conclusion:其实求next数组和匹...

网友评论

    本文标题:KMP中的next数组

    本文链接:https://www.haomeiwen.com/subject/fnivdctx.html