KMP----next数组 最长相同前后缀 递归求法解释

理解递归(推)求解next数组的代码是个难点,对于刚入门来说

next数组求解的时候是 已知next[0....j],next[j]=k.求解next[j+1]

首先next[j]=k的含义是说前j-1个字符最长相同前后缀是k,也说明前缀的最后一个字符下标是k-1

如果p[j]==p[k],那很明显是next[j+1]=k+1;

p[j]!=p[k]时,这时候

关键记住一句话:模式串的自我匹配

想一想KMP是怎么减少重复比较的,不就是移动的时候跳过一些元素吗,根据什么跳的,根据next数组跳的,为什么?因为模式串和文本串在失配前的字符是相等的!如果已经匹配相等的字符串里面有相同前后缀,那我不就可以拿前缀的最后一个字符的后一个字符 和失配字符 直接比较吗?

比如ADAC和ABAD

在C、D比较时候,失配了,是不是把ABAD往前移动 j-next[j] 等价于

也就是把 p[next[j]](在这里是p[1]也就是D)和当前字符D比较

 那么模式串 ADACADADFGH  在计算  ADACADAD  最长相同前后缀是多少

当发现C、D失配

此时就相当于 ADAC和ADAD作匹配 

也就是如下过程

C位置的next是1(ADA),也就是拿ADAC中的D来和 ADAD作匹配 

此时p[next[k]==p[j]    然后next=k+1=1+1=2

k=next[k]相当于KMP算法中的j-next[j],一个是“显式”移动,一个是直接改变p[k]中的下标,本质相同

代码如下

void GetNext(char* p,int next[])
{
    int pLen = strlen(p);
    next[0] = -1;
    int k = next[0];
    int j = 0;
    while (j < pLen - 1)
    {
        //p[k]表示前缀,p[j]表示后缀
        if (k == -1 || p[j] == p[k]) 
        {
            //++k;
            //++j;
            //next[j] = k;
            next[j+1] = k+1;
            k++;j++;
        }
        else 
        {
            k = next[k];
        }
    }
}

说白了,你不和我相配,我再递归找你前面有没有相同前缀后缀,一直找到next[0]=-1为止,此时next[j]=k+1=-1+1=0

你可能感兴趣的:(ACM,机试,练级)