KMP算法(Java实现)(困难)

前言:KMP算法原理理解容易但是代码实现很难理解,所以对每一段代码会使用很长的解释用来助于理解下面开始正题!

KMP 案例分解(图解说明)

S4-算法-KMP算法【2021-02-06】 - 简书 (jianshu.com)

KMP算法的原理如上,本章节具体讲解代码实现。

一、kmpNext数组实现代码:

 public static  int[] kmpNext(String dest){
        int[] next=new int[dest.length()];
        next[0]=0;
        for (int i = 1,j=0; i < dest.length(); i++) {
              while (j>0&&dest.charAt(i)!=dest.charAt(j)){
                  j=next[j-1];
              }
              //
              if (dest.charAt(i)==dest.charAt(j)){
                  j++;
               }
               next[i]=j;
            }
        return next;

        }

1、我们对要对 String str2 = "ABABA" 实现生成next数组的下标。首先进行next数组的初始化,

int[] next=new int[dest.length()];
next[0]=0;

2、对数组进行遍历使用双指针i,j将str2里的字符进行对比识别。

(1)

     

(2)

     

(3)

      

(4)

 

next数组已经出来了,next=[0, 0, 1, 2, 3]

二、kmpSeach数组实现代码:

    public static  int kmpSearch(String str1,String str2,int[] next){
        for (int i = 0, j = 0; i < str1.length ( ); i++) {
            // 情况分两种,一是不匹配到,要回溯;二是匹配到 索引 +1
            // 难点:情况一:当dest.charAt(i) !=dest.charAt(j),则需要 next[j-1] 得到新的 j
            while (j > 0 && str1.charAt (i) != str2.charAt (j)) {

            //这一步十分的精髓,当str1.charAt (i) != str2.charAt (j)就开始让j为下一次循环做准备
                j = next[j - 1];
            }

            // 情况二:匹配到,匹配值数量 +1
            if (str1.charAt (i) == str2.charAt (j)) {
                j++;
            }

            // 找到了
            if (j == str2.length ( )) {
                return i - j + 1;
            }
        }
        return -1;
    }

1、str1与str2字符串在通过i,j进行比对,当比对不上时进入 j = next[j - 1],再次比对,为什么是进入next[j-1]的下标呢,我们可以发现。i=6时,j=2时,不相等,j=next[j-1],j=0。i=7与j=0继续相比。如果是传统的暴力查找,我们要重新从i=5,j=0开始重新查找,不难发现步骤多了很多。

三、根据kmpSeach数组实现代码我们发现,在str1.charAt (i) != str2.charAt (j)的时候

j = next[j - 1]

这就意味着next[next.length-1]其实是没有用到的,我们可以之间对末尾初始化0,少一次遍历循环。

  public static  int[] kmpNext(String dest){
        int[] next=new int[dest.length()];
        //修改后
        next[0]=0;
        //修改后
        next[dest.length()-1]=0;
        //修改后
        for (int i = 1,j=0; i < dest.length()-1; i++) {
              while (j>0&&dest.charAt(i)!=dest.charAt(j)){
                  j=next[j-1];
              }
              //
              if (dest.charAt(i)==dest.charAt(j)){
                  j++;
               }
               next[i]=j;
            }
        return next;

        }

速度提升将近100ms,还是很可观的。

 完整代码如下:

import java.util.Arrays;

public class KMPAlgorithm {
    public static void main(String[] args) {
        String str1 = "ABCDAB ABABACDABDE";
        String str2 = "ABABA";
        int[] next=kmpNext(str2);
        System.out.println("next="+ Arrays.toString(next));

        int index=kmpSearch(str1,str2,next);
        System.out.println("index="+index);
    }

    public static  int kmpSearch(String str1,String str2,int[] next){
        for (int i = 0, j = 0; i < str1.length ( ); i++) {
            // 情况分两种,一是不匹配到,要回溯;二是匹配到 索引 +1
            // 难点:情况一:当dest.charAt(i) !=dest.charAt(j),则需要 next[j-1] 得到新的 j
            while (j > 0 && str1.charAt (i) != str2.charAt (j)) {
                //这一步十分的精髓,当str1.charAt (i) != str2.charAt (j)就开始让j为下一次循环做准备
                j = next[j - 1];
            }
            // 情况二:匹配到,匹配值数量 +1
            if (str1.charAt (i) == str2.charAt (j)) {
                j++;
            }
            // 找到了
            if (j == str2.length ( )) {
                return i - j + 1;// +1 因为索引从 0 开始,i 为 主串总长
            }
        }
        return -1;
    }


    //获取到一个字符串(字串)的部分匹配值
    public static  int[] kmpNext(String dest){
        int[] next=new int[dest.length()];
        //修改后
        next[0]=0;
        //修改后
        next[dest.length()-1]=0;
        //修改后
        for (int i = 1,j=0; i < dest.length()-1; i++) {
              while (j>0&&dest.charAt(i)!=dest.charAt(j)){
                  j=next[j-1];
              }
              //
              if (dest.charAt(i)==dest.charAt(j)){
                  j++;
               }
               next[i]=j;
            }
        return next;

        }


}

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值