KMP算法

KMP算法

 KMP算法就是利用一个next[]数组让子串str2没必要每次匹配失败之后都要去从头开始又和str1的下一个位置匹配,这样一种加速策略能够加速字符串的匹配。而next[]数组中,next[i]表示的是该位置之前的字符串中,前缀子串与后缀子串相同的最大长度。就比如下图,i位置的前缀子串与后缀子串相同的最大长度为2。也就是对于i来说,前缀从0开始往后走,后缀从i-1开始往前走,直到不相遇或者前缀后缀重合为止。
在这里插入图片描述
 而既然i位置前面这段后缀与从头开始的前缀相等,只是到了i位置之后才匹配不到,而i位置之前的匹配都已经通过了,说明匹配的母串str1中当前位置之前的那一段与i位置前面的这段是相等的,那么接下来的匹配就没有必要再回到开始去了,只需要去与i位置之前后缀相等的前缀的后一个位置j开始匹配就可以了。如下图所示
在这里插入图片描述
 next数组正是利用了这种思想来生成的,具体的next[]数组生成过程如下图所示:

在这里插入图片描述

 有了next[]数组之后,接下来就开始进行子串匹配。匹配过程如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
 代码如下:

public class KMP {
    public static int getStartIndex(String str1, String str2) {
    	//str1为空串的话,str2必然不为str1的子串
        if (str1.length() == 0) {
            return -1;
        }
        //str2为空串的话,其在str1中出现的位置必然为首位
        if (str2.length() == 0) {
            return 0;
        }
        //获取next[]数组
        int next[] = getNextArray(str2);
        int i = 0, j = 0;
        while (i < str1.length() && j < str2.length()) {
            //在该位置匹配成功,两个字符串都继续往下走
            if (str1.charAt(i) == str2.charAt(j)) {
                i++;
                j++;
            } else if (j == 0) {    //str2都调回到了初始位置还是没法和str1该位置匹配,说明i位置是真不行,str1需要往前走
                i++;
            } else {      //j往前跳,跳回到其最长相等前后缀中的前缀的后一位置
                j = next[j];
            }
        }
        //如果j走完s2了,说明匹配成功,子串初始位置是i-j,而j没走完的话则说明匹配不成功
        return j == str2.length() ? i - j : -1;
    }

    public static int[] getNextArray(String s) {
        if (s.length() == 1) {
            return new int[]{-1};
        }
        int[] next = new int[s.length()];
        //0号位置之前并没有前缀与后缀,设为-1
        next[0] = -1;
        //1号位置之前只有一个元素,即前缀与前缀相等,设为0
        next[1] = 0;
        int i = 2, k = 0;
        while (i < s.length()) {
            //i-1位置与要比较的位置的元素相等,说明该位置前面相等的前缀与后缀又增长了1,写入该位置
            if (s.charAt(i - 1) == s.charAt(k)) {
                next[i++] = ++k;
            } else if (k == 0) {       //已经比到头了,没有相等的前缀后缀
                next[i++] = 0;
            } else {              //往前跳去比
                k = next[k];
            }
        }
        return next;
    }

    public static void main(String[] args) {
        String str1 = "aaabacbaaabaaabacaaaabac";
        String str2 = "aaabacaaa";
        System.out.println(getStartIndex(str1, str2));
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

loser与你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值