关于KMP算法的思考

版权声明:本文为博主原创,未经博主允许不得转载。 https://blog.csdn.net/weixin_36904568/article/details/88707227

KMP算法解决的问题

假设主串为S,待比较的子串为s:

朴素匹配算法:如果使用朴素匹配算法,s和S每个字符逐一比较,如果有一个字符不相同,则s的下标和S的下标都会重新退回到0,再次进行比较。

KMP算法:KMP算法就是为了子串s能够快速的移动,不要从0开始比较。

KMP算法的依据

子串s能够快速移动的依据就是已匹配的子串的前n位能否等于匹配部分的主串的后n位。如果相同,则可以跳过中间部分,从这一相同的部分再次开始比较。

KMP算法的过程

举个栗子:

  假如现在S和s如下:

                  主串S:xxxxABDBABxxxxx
                  子串s:ABDBACF
  开始比较:

                          xxxxABDBABxxxxx
                              ABDBABF

1. 寻找匹配串:

我们可以发现,已匹配的子串s为:ABDBAB,匹配部分的主串S:ABDBAB

2. 分析前缀后缀

前缀:A AB ABD ABDB ABDBA
后缀:B AB BAB DBAB BDBAB

3. 找最大并且相同的前后缀

我们可以发现,AB为最大相同的前后缀

4. 跳过中间部分:

移动的距离为匹配的长度-刚才的前后缀长度
也就是 6-2=4

                          xxxxABDBABxxxxxxxxxx
                                    ABDBABF

KMP算法的实现

 //寻找回溯的下标
    public static int[] find_next(char[] s){
        int i = 0;                              //记录遍历字符串的下标,从0开始遍历
        int j = -1;                             //记录最大前后缀的下标,还没有开始匹配
        int[] next = new int[s.length+1];       //保存下标
        next[0] = -1;                           //初始化数组,子串中没有相同的字符
        while (i<s.length)
        {
            if(j == -1 || s[i] == s[j])         //找到匹配字符的最大前后缀,下标继续向前找
            {
                ++i;
                ++j;
                next[i] = j;
            }
            else                               //没有找到,开始回溯查找
                j = next[j];
        }
        return next;
    }


    //KMP匹配算法
    public static int index(char[] parent,char[] children,int[] next){
        int index = -1;                 //记录子串匹配父串的索引
        int plen = parent.length;
        int clen = children.length;
        int i = 0;                      //记录遍历主串的下标
        int j = -1;                     //记录子串需要回溯的下标
        while (i < plen && j <clen)
        {
            if(j == -1 || parent[i]==children[j])       //匹配字符成功
            {
                ++i;
                ++j;
            }
            else                        //匹配失败,根据next[]回溯
                j = next[j];
        }
        if(j>=clen)                     //完全匹配成功
            index = i-clen;
        return index;
    }

测试一下:

 public static void main(String[] args) {
        String parent = "xABDBAxxABDBABxxxxx";
        String children = "ABDBAB";
        int[] next = find_next(children.toCharArray());
        int index = index(parent.toCharArray(),children.toCharArray(),find_next(children.toCharArray()));
        System.out.println(index);
    }

结果为8

猜你喜欢

转载自blog.csdn.net/weixin_36904568/article/details/88707227