KMP算法

文章目录

  • next数组
  • 代码实现
  • next数组的优化

KMP 和 BF 不一样的地方在,主串的的下标 i 并不会回退,只需要让子串的下标 j 回退就够了(通过一个next数组找到回退的位置)

next数组

用来保存子串匹配失败后,回退的位置

求法

  • next数组0下标的值可以是任意数字,代码实现的时候会处理(之后都以 next[0] == -1为例)
  • next[1] == 0
  • 一个真子串从子串的 0 下标开始,另一个真子串以子串的 j-1 下标的字符结尾,找到两个相同的真子串(不是同一个)。next数组其他下标的值就是真子串的长度

练习1
”a b a b c a b c d a b c d e”, 求其的 next 数组
-1 0 0 1 2 0 1 2 0 0 1 2 0 0

练习2
”a b c a b c a b c a b c d a b c d e”,求其的 next 数组
-1 0 0 0 1 2 3 4 5 6 7 8 9 0 1 2 3 0

接下来的问题就是,已知next[ j-1 ] = k ; 怎么求next [ j ] = ?
因为next[ j-1 ] = k,设子串为p
则p[0]…p[ k-1 ] = p[ j-1-k ]…p[ j-2 ]

  • 当p[ k ] == p[ j-1 ] 时
    p[0]…p[ k ] == p[ j-1-k ]…p[ j-1 ]
    p[0]…p[ (k-1)+1 ] == p[ j-1-k ]…p[ (j-2)+1 ]
    得出 next[ j ] == k+1
  • 当p[ k ] != p[ j-1 ] 时
    一直回退,去找p[ j-1 ]==p[ k ], 然后有next[ j ] = k+1

代码实现

public class Test {
    public static void getNext(String sub, int[] next) {
        next[0] = -1;
        next[1] = 0;
        int j = 2;//当前要计算 k的j下标
        int k = 0;//前一项的 k
        while (j < sub.length()) {
            if (k == -1 || sub.charAt(j - 1) == sub.charAt(k)) {
                next[j++] = ++k;
            } else {
                k = next[k];
            }
        }
    }

    /**
     * @param str 主串
     * @param sub 子串
     * @param pos 从主串的pos位置开始匹配
     * @return 找到子串在主串当中第一次出现的下标
     */
    public static int KMP(String str, String sub, int pos) {
        if (str == null || sub == null) return -1;
        int lenStr = str.length();
        int lenSub = sub.length();
        if (lenStr == 0 || lenSub == 0) return -1;
        if (pos < 0 || pos >= lenStr) return -1;

        int[] next = new int[lenSub];
        getNext(sub, next);

        int i = pos;//遍历主串
        int j = 0;//遍历子串
        while (i < lenStr && j < lenSub) {
            if (j == -1 || str.charAt(i) == sub.charAt(j)) {
                i++;
                j++;
            } else {
                j = next[j];
            }
        }
        if (j >= lenSub) {
            return i - j;
        }
        return -1;
    }
}

next数组的优化

next 数组的优化,即如何得到 nextval 数组:

1.回退到的位置和当前字符一样,就写回退的那个位置的nextval值
2.如果回退的位置和当前字符不一样,就写当前字符原来的next值

KMP算法_第1张图片
KMP算法_第2张图片

你可能感兴趣的:(算法,算法)