栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

KMP算法和next数组详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

KMP算法和next数组详解

KMP算法主要是用来求解子串在主串中第一次出现的位置,并返回这个子串的位置的一种提高效率的方法。在讲解KMP算法之前,我们先来看看求子串在主串中位置的一般解法,即暴力解法。

 

1.暴力解法

 public static int BF(String str,String sub){
        if(str == null || sub == null){
            return -1;
        }
        int lenStr = str.length();
        int lenSub = sub.length();
        if(lenStr == 0 ||  lenSub == 0){
            return -1;
        }
        int i = 0;
        int j = 0;
        while (i < lenStr && j < lenSub ){
            if(str.charAt(i) == sub.charAt(j)){
                i++;
                j++;
            }else {
                i = i - j + 1;
                j = 0;
            }
        }
        if(j >= lenSub){
            return i-j;
        }
        return -1;
    }
    public static void main(String[] args) {
        System.out.println(BF("ababcabcdabcde","abcd"));
        System.out.println(BF("ababcabcdabcde","abcf"));
        System.out.println(BF("ababcabcdabcde","ab"));
    }

 2.KMP算法

        KMP算法和暴力解法的区别就是,在暴力解法主串中如果i和子串j中不匹配,则i返回到开始匹配的地方并+1,但KMP中不用返回,继续保持在原位。在子串中的j会返回到一个“特殊”位置,而这个特殊位置就是我们接下来要讲的。

首先我们看看什么叫next数组:

2.1next数组的含义:

 2.2next数组练习

(1).  k值的求法:找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标0开始,一个以下标j-1结尾。

(2).  不管什么时候next[0]都=-1,next[1]=0.

2.2.1例题1

 例题2:

 2.3求解数组next[i+1]的值

         我们通过上面自己的计算可以求得next[i+1]数组得值,但是我们用程序就需要一个函数来解决,下面我们来求其函数:

 推导过程:从上图之第一次k退回到p[3]的位置,假设p[i] == p[k]

 那如果p[i] != p[k]时:next[i+1]=什么呢?

3.java来实现代码 第一步:进入遍历主串和子串的条件
//首先我们先来列出条件
 public static int KMP(String str,String sub,int pos){
        if(str == null || sub ==null){
            return -1;
        }
        int lenStr = str.length();
        int lenSub = sub.length();
        if(lenStr == 0 || lenSub == 0){
            return  -1;
        }
         if(pos < 0 || pos >= lenStr){
            return -1;
        }
第二步:进行主串和子串的遍历
 int i = pos;//遍历主串
         int j = 0;//遍历子串
         while (i < lenStr && j < lenSub){
             //j==-1表示一开始就匹配失败
             if(j==-1 || str.charAt(i) == sub.charAt(j)){
                 i++;
                 j++;
             }else {
                 j = next[j];
             }
         }
         if(j >= lenSub){
          return i-j;
      }
         return -1;
    }
第三步:写出next数组,来保存子串j回退的位置
int [] next = new int[lenSub];
getNext(sub,next);//求得j回退得位置
 public static void getNext(String sub,int[] next){
        next[0] = -1;//开始的next[0]默认是-1
        next[1] = 0;//默认next[1]是0
        int i = 2;//默认i从第三个位置开始
        int k = 0;
        for (; i < sub.length();i++) {
            //p[i-1] == p[k];
            //这里是sub.charAt(i - 1)是因为之前i是从第三个位置开始的,要用i的前一项
             if (k==-1 || sub.charAt(i - 1) == sub.charAt(k)) {
                   next[i] = k+1;//之前计算得都是next[i+1]=k+1,这里是因为i是第三个位置开始 
                                  //得,因此是next[i]=k+1;
                   k++;
                   i++;
            }else{
                 k = next[k];//如果第一次退回的k和之前的sub.charAt(i-1)不同,则继续往下退
            }
        }
    }
4.next的简化数组nextval数组

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/695483.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号