KMP算法详述

KMP

1.应用

给定两个字符串s1,s2,判断s2是否是s1的字串,若存在则返回在s2在s1中的起始下标,不存在则返回-1

2.概念引入

最长前缀和最长后缀的匹配长度

字符串:abbabb(不考虑自身长度的前缀后缀)

12345
前缀aababbabbaabbab
后缀bbbabbabbabbabb

从上表中可知字符串abbabb的最长前缀和最长后缀的匹配长度为3

3.流程

经典流程

s1     a b b b a b b b l ...
index  i...            x
s2     a b b b a b b b q ...
       0...            y
当我们匹配到x位置和y位置时我们发现不相等于是 s1回到 i+1位置 ,s2回到 0位置接着进行比较
时间复杂度O(n*m)

KMP流程

1.我们对s2计算每个位置最长前缀和最长后缀,结果记录next数组

s1     a b b b a b b b l ...
index  i...            x
s2     a b b b a b b b q ...
       0 1 2 3 4 5 6 7 8           
  										 y
 next -1 0 0 0 0 1 2 3 4
当我们匹配到x位置和y位置时我们发现不相等于是s1原地不动,s2回到next[y]位置,s1原地不动,接着进行比较,相当于我们把s2推进
  s1     a b b b a b b b l ...
          s2     a b b b a b b b q ...
           next -1 0 0 0 0 1 2 3 4
  index                  y
此时我们发现l != a,于是s1原地不动,s2回到next[y]位置,s1原地不动,接着进行比较,相当于我们把s2推进
    s1     a b b b a b b b l ...
                    s2     a b b b a b b b q ...
    index                  y
此时我们发现l != a,此时next[y]=-1,代表s2已经推不动了,您老s1移动到x+1位置吧(?位置)
  s1     a b b b a b b b l ? ...
                    s2     a b b b a b b b q ...

4.代码实现

public class KMP {
    public static int getIndexOf(String s1,String s2){
        if(s2.length()>s1.length() || s1==null || s2==null || s1.length()<1){
            return -1;
        }
        int[] nextArr = getNextArr(s2);
        char[] chs1 = s1.toCharArray();
        char[] chs2 = s2.toCharArray();
        int i1=0;
        int i2=0;
        while(i1<s1.length() && i2<s2.length()){
            if(chs1[i1]==chs2[i2]){
                i1++;
                i2++;
            }else if(nextArr[i2]!=-1){
                i2=nextArr[i2];
            }else{
                i1++;
            }
        }
        return i2==s2.length()?i1-i2:-1;
    }

    public static int[] getNextArr(String s){
        if(s.length()==1)return new int[]{-1};
        int[] next=new int[s.length()];
        next[0]=-1;
        next[1]=0;
        int cn=0;//当前要和i-1比较的位置
        int i=2;
        char[] chs = s.toCharArray();
        while(i<chs.length){
            if(chs[cn]==chs[i-1]){
                next[i++]=++cn; //i位置的值已经确定下来了
            }else if(cn>0){
                cn=next[cn];
            }else{
                next[i++]=0;//没有与当前位置相同的字符
            }
        }
        return next;
    }

    public static void main(String[] args) {
        System.out.println(getIndexOf("lanqianyaochengweijiagoushi", "jiagoushi"));
    }

}

如有错误,欢迎大家在评论区交流哦😊

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值