KMP算法

作用

给一个主串、一个子串,判断子串在主串中出现的位置,没有匹配则返回-1.

示例

主串:BBCABCDABABCDABCDABDE
子串:ABCDABD
输出:13

next数组手动求的话不需要用下面代码中那么高级的求法,杀鸡何用牛刀

子串字符 A B C D A B D
下标x 0 1 2 3 4 5 6
next [x] -1 0 0 0 0 1 2

代码

package 字符串;

public class 模式匹配 {
    public static void main(String[] args) {
        new 模式匹配().exe();
    }

    private void exe() {
        int r1 = simple_index2("BBCABCDABABCDABCDABDE", "ABCDABD");
        System.out.println("simple_index_result="+r1);
        int r2 = kmp_index("BBCABCDABABCDABCDABDE", "ABCDABD");
        System.out.println("kmp_index_result="+r2);
    }

    /**
     * 简单模式匹配
     * 子串在主串中开始出现的位置可能是[0,n-1],简单模式匹配就是对每个位置逐个判断
     * @param str
     * @param subStr
     * @return
     */
    private int simple_index(String str, String subStr) {
        // i:指示器,指示主串中位置
        // j:指示器,指示子串中的位置
        int i = 0, j = 0;
        while (i < str.length() && j < subStr.length()) {
            if (str.charAt(i) == subStr.charAt(j)) {
                i++;
                j++;
            } else {
                i = i - j + 1;
                j = 0;
            }
        }
        if (j == subStr.length()) {
            return i - j;
        } else {
            return -1;
        }
    }

    private int simple_index2(String str, String subStr) {
        int i = 0, j = 0;
        // 标记str与substr本趟匹配开始的位置
        int k = 0;
        // 模式串在主串中的开始的位置可能是[0,str.length()-1],逐个进行判断
        while (i < str.length() && j < subStr.length()) {
            if (str.charAt(i) == subStr.charAt(j)) {
                i++;
                j++;
            } else {
                // i = i - j + 1;
                i = ++k;
                j = 0;
            }
        }
        if (j == subStr.length()) {
            // return i - j;
            return k;
        } else {
            return -1;
        }
    }

    /**
     * 目的:保持i不动,通过调整j来消除i处的不匹配
     * 
     * @param str
     * @param subStr
     * @return
     */
    private int kmp_index(String str, String subStr) {
        // next数组
        int[] next = getNext(subStr);
        // 主串
        char[] strArr = str.toCharArray();
        // 子串
        char[] subStrArr = subStr.toCharArray();
        int i = 0, j = 0;
        while (i < str.length() && j < subStr.length()) {
            if (strArr[i] == subStrArr[j]) {
                // 该位相等
                i++;
                j++;
            } else {
                // 不等:kmp的目标是i不动,通过调整j使得调整能够继续
                j = next[j];
                // 但是next数组中标记了一种特殊情况:那就是当next[x]=-1时表示此时应该:i++;j=0
                if (j == -1) {
                    i++;
                    j = 0;
                }
            }
        }
        if (j == subStr.length()) {
            // 说明子串在主串中
            return i - subStr.length();
        }
        return -1;
    }

    /**
     * 得到next数组
     * 
     * @param subStr
     * @return
     */
    private int[] getNext(String subStr) {
        int n=subStr.length();
        int[] next = new int[n];
        next[0] = -1;
        char[] subStrArr = subStr.toCharArray();
        int i = 0, j = -1;
        while (i < n-1) {// 这里要i

参考文献

字符串匹配算法KMP
王道论坛_数据结构
汪都能看懂的KMP

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