KMP算法

描述

字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)

假设字符串str长度为N,字符串match长度为MM <= N

想确定str中是否有某个子串是等于match的,有返回匹配索引位置

时间复杂度 O(N)

举例

str: aabaabaac

match: aaba

返回3,即str的索引3位置

具体步骤

KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的

求出match串的next数组,进行加速匹配

next数组

next数组是match串的前缀与后缀相同记录信息,即记录则每个位置的前面字符串,前缀与后缀相同的最大字符串数量【前缀不包含本身】

举例:match串为 aabaabsaabt,它的next数组应该是 [-1,0,1,0,1,2,3,0,1,2,3]

图示如下:

KMP算法_第1张图片

kmp主体

现在有了match串的next数组

就进行匹配过程

为了简单,match串为 aabaab ,next数组为 [-1,0,1,0,2]

str串为 bcaabaataabaab

x表示str串的匹配来到位置

y表示为match串匹配来到的位置

图解流程

KMP算法_第2张图片

为什么match数组匹配不成功时会退为next[y]

比如在3状态经过3过程调整到4状态时,即y在5,x在7位置时,match[5] = b 不等于 str[7] = t,接着y跳转到next[5] = 2位置,y来到 2位置,match[2] = b

因为

next 求得是前缀与后缀相等的最大缀字符串数;

而既然匹配到当前位置,那么说明match串当前位置的前面位置是在str中能匹配上的,而match串中前缀与后缀相同的记录,那么match前缀一定与str当前位置前面相同,因为str前面位置是后缀,

这样直接跳过前缀的匹配,进而加速整个过程

code实现

next数组code实现思路

很明显,按照先前的思路设计代码,next的求解太耗费时间

那么next数组是否存在空间位置依赖呢,进而用动态规划得到next数组

必然是有的

过程描述:

求i位置的next值时,查看i-1位置的next[i-1],记为c,【c即为i位置的前缀匹配个数,也是str中前缀后一个位置的数的下标】

匹配str[c]和str[i-1],如果相等,那么next[i] = c+1;如果不相等,继续会退c,即c = next[c]

直到无法回退,next[i] = c+1

图示如下:

KMP算法_第3张图片

KMP算法_第4张图片

KMP算法_第5张图片

KMP算法_第6张图片

KMP算法_第7张图片

KMP算法_第8张图片

kmp code
    public static int getIndexOf(String str,String match){
        //合法判断
        if(str == null || str.length() == 0 || match == null || match.length() > str.length())
            return -1;
        //O(N)
        char[] str1 = str.toCharArray();
        char[] str2 = match.toCharArray();
        //O(N)
        int [] next = getNextArray(str2);
        int x = 0;
        int y = 0;
        //O(N)
        while (x < str1.length){

            if(str1[x] == str2[y]){
                x++;
                y++;
            }else if (next[y] == -1) {
                x++;
            } else {
                y = next[y];
            }
        }
        return y == str2.length ? x - y : -1;
    }

   public static int[] getNextArray(char[] str) {
        if(str == null || str.length == 0)return null;
        if(str.length == 1)return new int[]{-1};

        int [] next = new int[str.length];
        //初始值
        next[0] = -1;
        next[1] = 0;

        int i = 2;
        int c = 0;
        while (i < str.length){

            if(str[i-1] == str[c]){
                next[i++] = ++c;
            }else if(c > 0){
                c = next[c];
            }else{
                next[i++] = 0;
            }
        }
        return next;
    }


你可能感兴趣的:(算法,数据结构,java,算法)