lukazan

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1、next数组求解

  对于模式串T,next[j]代表了T的前j个字符组成的子串中,其前缀和后缀的最长公共串的长度。

(1) 求解字符串T的next数组的算法如下:

  1. next[0]=-1, next[1]=0。
  2. 在求解next[j]时,令k=next[j-1],
  3. 比较T[j-1]与T[k]的值,
    1. 若T[j-1]等于T[k],则next[j]=k+1。
    2. 若T[j-1]不等于T[k],令k=next[k],若k等于-1,则next[j]=0,否则跳至3。

(2) 下面以模式串T=“abaabcac”为例,给出求next数组的过程:

  1. next[0]=-1, next[1]=0。
  2. 当j=2时,k=next[j-1]=next[1]=0,由于T[j-1]=T[1]=‘b’,T[k]=T[0]=‘a’,T[j-1]不等于T[k],令k=next[k]=next[0]=-1,因此next[2]=0。
  3. 当j=3时,k=next[j-1]=next[2]=0,由于T[j-1]=T[2]=‘a’,T[k]=T[0]=‘a’,T[j-1]等于T[k],因此next[3]=k+1=1。
  4. 当j=4时,k=next[j-1]=next[3]=1,由于T[j-1]=T[3]=‘a’,T[k]=T[1]=‘b’,T[j-1]不等于T[k],令k=next[k]=next[1]=0。此时T[k]=T[0]=‘a’,T[j-1]等于T[k],因此next[4]=k+1=1。
  5. 当j=5时,k=next[j-1]=next[4]=1,由于T[j-1]=T[4]=‘b’,T[k]=T[1]=‘b’,T[j-1]等于T[k],因此next[5]=k+1=2。
  6. 当j=6时,k=next[j-1]=next[5]=2,由于T[j-1]=T[5]=‘c’,T[k]=T[2]=‘a’,T[j-1]不等于T[k],令k=next[k]=next[2]=0。此时T[k]=T[0]=‘a’,T[j-1]不等于T[k],再令k=next[k]=next[0]=-1,因此next[6]=0。
  7. 当j=7时,k=next[j-1]=next[6]=0,由于T[j-1]=T[6]=‘a’,T[k]=T[0]=‘a’,T[j-1]等于T[k],因此next[7]=k+1=1。

(3) java代码实现

public class KMP {

    /**
     * 求出一个字符数组的next数组
     * @param t 字符数组
     * @return next数组
     */
    public static int[] getNextArray(char[] t) {
        int[] next = new int[t.length];
        next[0] = -1;
        next[1] = 0;
        int k;
        for (int j = 2; j < t.length; j++) {
            k=next[j-1];
            while (k!=-1) {
                if (t[j - 1] == t[k]) {
                    next[j] = k + 1;
                    break;
                }
                else {
                    k = next[k];
                }
                next[j] = 0;  //当k==-1而跳出循环时,next[j] = 0,否则next[j]会在break之前被赋值
            }
        }
        return next;
    }

    /**
     * 对主串s和模式串t进行KMP模式匹配
     * @param s 主串
     * @param t 模式串
     * @return 若匹配成功,返回t在s中的位置(第一个相同字符对应的位置),若匹配失败,返回-1
     */
    public static int kmpMatch(String s, String t){
        char[] s_arr = s.toCharArray();
        char[] t_arr = t.toCharArray();
        int[] next = getNextArray(t_arr);
        int i = 0, j = 0;
        while (i<s_arr.length && j<t_arr.length){
            if(j == -1 || s_arr[i]==t_arr[j]){
                i++;
                j++;
            }
            else
                j = next[j];
        }
        if(j == t_arr.length)
            return i-j;
        else
            return -1;
    }

    public static void main(String[] args) {
        System.out.println(kmpMatch("abcabaabaabcacb", "abaabcac"));
    }

}

2、KMP算法执行匹配过程

  将next数组全部求出之后,只需在简单的匹配算法上稍作修改,便得到了KMP的匹配算法:当模式串T匹配至第j个字符时匹配失败,i指针不变,将j指针置为next[j]的值,若j的值为-1,则将i和j同时加1。随后继续进行逐个的比较。

 

posted on 2021-04-20 13:52  lukazan  阅读(59)  评论(0编辑  收藏  举报