KMP算法

作者: 四喜汤圆 | 来源:发表于2018-08-21 15:29 被阅读6次

    作用

    给一个主串、一个子串,判断子串在主串中出现的位置,没有匹配则返回-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<n-1,一开始写的i<n导致最后数组越界了
                if ( (j == -1) || (subStrArr[i] == subStrArr[j]) ) {
                    // j==-1时:从数组中取元素都要越界了,还不赶紧前进一位!!
                    i++;
                    j++;
                    next[i] = j;
                } else {
                    j = next[j];
                }
            }
            return next;
        }
    
    }
    

    参考文献

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

    相关文章

      网友评论

          本文标题:KMP算法

          本文链接:https://www.haomeiwen.com/subject/rihjiftx.html