土味KMP

土味KMP

本文是我对KMP的一点理解,KMP是用于字符串匹配的一种算法,而KMP的精髓就在于求解NEXT数组(即跳表),别的都是一看就懂,而NEXT数组使用时最关键的一句代码就是K=NEXT[K],理解了这个,KMP基本就懂了。(我的建议是自己画一遍KMP的匹配流程,这样很容易就懂了)

我比较喜欢简洁的东西,网上那种介绍KMP的博客不知道为啥篇幅很长,我直接没有看的欲望。这里还是先说下KMP设计的定义,模式串:你想要查找的字符串,文本串:给定的文本串,举个例子,你想要在字符串“abcdabd”中查询字符串"dab"的位置,那“abcdabd”就是文本串,“dab"就是模式串,然后next数组的值是什么意思呢,next[i]就代表模式串中前i个字符的最长匹配前缀后缀长度,还是举个例子,比如模式串是"abcdabd”,那么有7个字符,next数组的长度也是7,next[0]一直到next[6],那么next[6]=2,因为在能匹配的前缀和后缀中,“ab"最长,长度为2,注意:前缀不能是字符串本身,即"abcdab"的最长的前缀为"abcda”,为什么呢,大家是这么规定的,可能比较方便。顺带提一下,根据next数组的定义,next[0]=-1(这也是约定俗成),next[1]=0。那么如何求解next数组呢,下面是我的代码,个人感觉是比较贴合定义的,很好理解。

(ps:之前贴上来的代码格式没弄好,写的也有问题,这里重新编辑一下)

public static void main(String[] args) {
        System.out.println(kmp("ababcabcacbab","bcabc"));
    }

    public static int kmp(String s,String moshistr){
        //next数组只需要这么长的原因是:判定最后一个字符时只需要用到next[moshistr.length-1],所以next数组长度这样定义
        int[] next = new int[moshistr.length()];
        getnext(moshistr,next);
        int j=0;
        for (int i=0;i<s.length();i++){
            //跳出该while循环表示要么i,j匹配成功,要么j==-1(说明一直整个模式串都和i所对应的字符不匹配)
            while ((j!=-1)&&s.charAt(i)!=moshistr.charAt(j)){
                j=next[j];
            }
            j++;
            //返回模式串在查询串匹配时的起始下标
            if (j==moshistr.length()){
                return i-j+1;
            }
        }
        return -1;
    }

    //next[i]代表模式串s中前i个字符的next值(即前i个字符的最长前缀后缀匹配)
    //next长度为s.length()+1
    //这里是直接用最长前缀后缀的定义求解next
    public static void getnext(String s,int[] next){
        next[0]=-1;//next[1]默认为0
        for (int i=2;i<s.length();i++){
            int j=next[i-1];
            while (j!=-1&&s.charAt(i-1)!=s.charAt(j)){
                j=next[j];
            }
            if (j==-1){
                j++;
            }
            //如果匹配成功则赋值,否则默认值为0
            if (s.charAt(i-1)==s.charAt(j)){
                next[i]=++j;
            }
        }
        System.out.println();
        for (int x:next){
            System.out.print(x+" ");
        }
        System.out.println();
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值