KMP算法之next数组的求解

1.假设模式串(子串)p: 为 "bbabba" ,扫描模式串的指针为j, 当扫描到模式串不匹配的时候模式串回退的位置为k

需要弄清楚的是next数组的含义,比如next[j] = k表示的是当p[j] == p[k]的判断不成立的时候(失配)k应该回退到模式串的下标为k的next[k]位置上

比如模式串为bbabba,下面是求解过程

                 b b a b b a

    (p[k]为该行中字后一个字符,写成下面的形式是为了更好的观察,其实还是同一个字符串)  

    p[0] = b                               b    netx[0] = -1   j = 0 k = -1

    p[1] = b                           b  b    next[1] = 0    j = 1 k = 0

    p[2] = a                        b b  a    next[2] = 1    j = 2  k = 1

    p[3] = b                     b b a  b    next[3] = 0    j = 3 k = 0 

    p[4] = a                  b b a b  a    next[4] = 2    j = 4 k = 1

    p[5] = a               b  b a b b a    next[1] = 2    j = 5 k = 2

要求解next[2],首先要看上一次的p[j]和p[k] 其中上一次的j和k为:j = 1 k = 0

判断p[1]是否等于p[0] 假如相等则next[2] = ++k = 1,  假如不相等k = next[k],在这里例子中p[1] = p[0] ,所以next[2] = ++k = 1     

求解next[3] , 其中next[2] = 1 : j = 2 k = 1 那么判断p[2]是否等于p[1] ,这里p[2]!=p[1]所以 j = 2 k = next[1] = 0 判断p[2] 是否等于p[0] 发现不等那么j = 2 k = next[0] = -1,此时  k = -1,当k = -1 的时候next[3] = ++k = 0 

求解next[4], 其中next[3] = 0 : j = 3 k = 0 那么判断p[3]是否等于p[0] 发现相等那么next[4] = ++k = 1

求解next[5], 其中next[4] = 1 : j = 4 k = 1 那么判断p[4]是否等于p[1] 发现相等那么next[5] = ++k = 2

那么模式串 "bbabba"的next数组为 : -1 0 1 0 1 2 

上面的模式是基于代码的思路来的

求解next数组实际上也是求解最长前缀与最长后缀的最长匹配,比如像上面的模式串 "bbabba"(求解next[k]不包含模式串下标为k这个位置的字符所求解的前缀和后缀)

第一次next[0]]:  b  next[0] = -1 

第二次next[1]:  bb next[1] = 0

第三次next[2]:  bba 求解next[2]的时候不包括bba的最后一个字符,所以bba的前缀为:  b 

后缀为b 所以最长前缀与最长后缀的最长匹配为b,有一个所以next[2] = 1

第四次next[3]:  bbab   bbab的前缀为: b和bb

后缀为a和ba,前缀和后缀都不匹配,所以next[3] = 0

第五次next[4]:  bbabb   bbabb的前缀为: b, bb,bba

后缀为b,ab,bab,所以最长前缀与最长后缀的最长匹配为b,有一个所以next[4] = 1

第六次next[5]:  bbabba   bbabba的前缀为: b, bb,bba,bbab

后缀为b,bb,abb,babb,所以最长前缀与最长后缀的最长匹配为bb,所以next[5] = 2

2. 下面是具体的代码实现:

public class Next{
    public static void main(String[] args) {
        String p = "bababb";    //next:-1 0 0 1 2 3
        int next[] = next(p);
        for(int i = 0;i<next.length;i++){
            System.out.print(next[i]+" ");
        }
    }

    private static int[] next(String ps){
        char p[] = ps.toCharArray();
        int next[] = new int[ps.length()];
        next[0] = -1;
        if(p.length==1)return next;
        //定义两个指针用来指向扫描到模式串和假如不匹配会回退到的位置k
        int j = 1;
        int k = 0;
        //因为下面++j所以j<next.length-1
        while(j<next.length-1){
            if(k==-1||(p[j]==p[k])){
                next[++j]=++k;
            }else{
                k = next[k];
            }
        }
        return next;
    }
}
 

其中还有其他例子:

String p = "ababaa";  //next:-1 0 0 1 2 3
String p = "bababb";  //next:-1 0 0 1 2 3
String p = "bbabba";  //next:-1 0 1 0 1 2
String p = "babbab";  //next:-1 0 0 1 1 2

想的时候可以求解next数组的时候是求解最长前缀与最长后缀的重叠部分

猜你喜欢

转载自blog.csdn.net/qq_39445165/article/details/82464967