算法 :字符串匹配 【kmp】

KMP

字符串快速匹配算法

上面的字符串为较长的字符串,需要查找其中是否包含下面较短的字符串。

在这里插入图片描述
e != w 第一次右移

在这里插入图片描述

e != t 第二次右移

在这里插入图片描述
e != s 并且 s 没有前缀和后缀相同,为0。就把下面的字符串0位置的字符比较。

在这里插入图片描述
还是不相等,只能往后从头开始重新匹配,放弃掉之前的字符串。

在这里插入图片描述

求next数组

在这里插入图片描述
计算i下标的值需要依靠前面 i - 1 数组上的值cn (cn= next[i-1]) 。

比较 chars[i - 1] 与 chars[cn] 三种情况:

  1. chars[i-1] == chars[cn] 说明前缀和又可以增加,并且将 i 和 cn 都+1 进行下一次比较

    next[i++] == ++cn
    
  2. chars[i-1] != chars[cn] ,但是 cn > 0 ,说明前面还有前缀和后缀相等的情况,i2往前跳进行比较

    cn = next[cn]
    
  3. chars[i-1] != chars[cn] ,但是 cn = 0 ,说明真的没有相同的前缀和后缀相同了。next[i]数组置为0,往后继续。

    next[i++] = 0
    

在这里插入图片描述

代码如下:

public class Kmp {
    public static int kmp(String s1, String s2){
        if(s1 == null || s2 == null || s2.length() < 1 || s1.length() < s2.length()){
            return -1;
        }
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        int[] next = getNextArr(s2.toCharArray());
        int i1 = 0;
        int i2 = 0;
        while (i1 < s1.length() && i2 < s2.length()){
            if(str1[i1] == str2[i2]){
                i1++;
                i2++;
            }else if(i2 == 0){
                i1++;
            }else {
                i2 = next[i2];
            }
        }
        return i2 == str2.length ? i1 - i2 : -1;
    }

    // 获得最大前缀和后缀和的数组
    public static int[] getNextArr(char[] chars){
        if(chars.length == 1){
            return new int[]{};
        }

        int[] next = new int[chars.length];
        next[0] = -1;
        next[1] = 0;
        int cn = 0;
        for (int i = 2; i < chars.length; i++) {
            if(chars[i-1] == chars[cn]){
                next[i++] = ++cn;
            }else if(cn > 0){
                cn = next[cn];
            }else{
                next[i++] = 0;
            }
        }
        return next;
    }

    public static void main(String[] args) {
        String s1 = "abbsabbtcabbsabbeabbsabbtcabbsabbfabbsabbtcabbsabbw";
        String s2 = "abbsabbtcabbsabbw";
        int kmp = kmp(s1, s2);
        System.out.println(kmp);
    }
}

左神(左程云)耗时100天打造算法与数据结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值