改进的KMP

来源:互联网 发布:淘宝销量为0敢买吗 编辑:程序博客网 时间:2024/05/21 06:03

KMP改进主要是对next数组进行改进
这里写图片描述
这里写图片描述
如图当s[3]与p[3]不匹配时,根据next[3]=1,所以继续把s[3]与p[1]进行比较,即把模式串右移j-k=3-1=2位,此时s[3]与p[1]还是不等。其实仔细想一想,这是必然的,为什么呢?
因为当j=3时,p[j]=p[next[j]]即p[3]=p[1],问题就出在这里,当s[i]!=p[j],又因为p[j]=p[next[j]],所以p[next[j]]!=s[i]。所以可以对程序进行优化。如果出现了p[j] = p[ next[j] ],则需要再次递归,即令next[j] = next[ next[j] ]。
优化之前

public static int [] getNext(String p){        int plen=p.length();        char[] parray = p.toCharArray();        int [] next=new int [plen];        next[0]=-1;        int k=-1,j=0;        /**        首先要明白next[j]=k是什么意思,简单概述就是:当主串s和模式串p比较时,当s[i]!=p[j]时,        (我们不采用蛮力法时)我们的主串s的s[i]字符接下来该和模式串的p[k]字符进行比较,即我们        不再是像蛮力法那样,每次把模式串右移一个字符,再回溯到主串的下一个字符进行比较。采用KMP        算法,我们不需要回溯主串,而是直接把模式串右移j-k(j-next[j])个位置,进行下次比较。        也就是说当s[i]!=p[j]的时候,接下来我们让s[i]和p[k](p[next[j]])进行比较。        那么我们我们应该怎么求解next数组呢?已知next[j]=k,我们可以采用递归的方式求next[j+1]的值        注意next[j]=k意味着p[0]p[1]p[2]....p[k-1]=p[j-k]....p[j-1],=左右各有k个值        所以当求next[j+1]的时候,就需要比较p[0]p[1]p[2]....p[k-1]p[k]=p[j-k]....p[j-1]p[j]        又因为p[0]p[1]p[2]....p[k-1]=p[j-k]....p[j-1]相等,所以只需要比较p[k]和p[j]        假如p[k]=p[j],则next[j+1]=k+1,        假如p[k]!=p[j],令k=next[k],此时再比较p[j]与p[k],假如如果不相等,则继续递归前缀索引,        令 k=next[k],继续判断,直至k=-1(即k=next[0])或者p[j]=p[k]为止。         */        while(j<plen-1){//对于数组next长度为plen所以当一个循环不满足条件时,j=plen-1,刚好是next数组的最后一个。            if(k==-1||parray[j]==parray[k]){//因为不可能p[0]和p[-1]比较,所以用k==-1                k++;                j++;                next[j]=k;//next[j+1]=k+1            }else{                k=next[k];            }        }        return next;    }

优化之后的

public static int[] getNext1(String p){        int plen=p.length();        char[] parray = p.toCharArray();        int [] next=new int[plen];        next[0]=-1;        int k=-1,j=0;        while(j<plen-1){            if(k==-1||parray[j]==parray[k]){                k++;                j++;                if(parray[j]!=parray[k]){//相当于判断p[j]!=p[next[j]]                    next[j]=k;                }else{                    next[j]=next[k];                }               }else{                k=next[k];            }        }        return next;    }
原创粉丝点击