KMP算法

KMP算法是用来判断子串是否存在于主串中,KMP算法核心是对子串进行自检,生成next数组,从而和主串进行比较时减少没必要的操作从而提高效率。下面看一个示例,看说明下next数组:

/**
 * KMP算法:
 *      两个字符串,主串:cfrababaaaba 子串:ababaaaba,判断主串是否包含子串,若包含返回起始下标,否则返回-1
 */
public class KmpAlgorithm {
     /**
     * 根据给定的子串数组T,自检得到next数组
     * @return
     */
    public static int[] getNext(char[] T){
        //定义两个索引变量,i表示后继,j表示前继
        int i=1, j=0;
        int[] next = new int[T.length];
    
        next[1] = 0;
        while(i< T[0]){
            if(j ==0 || T[i] == T[j]){
                i++;
                j++;
                next[i] = j;
            }else{
                //j 回溯
                j = next[j];
            }
        }
        return next;
    }

    public static int kmp_search(String mainString, String subString){
        char[] S = new char[mainString.length()+1];
        S[0] = (char)mainString.length();
        char[] T = new char[subString.length()+1];
        T[0] = (char)subString.length();

        int i = 0;
        for(char s:mainString.toCharArray()){
            i++;
            S[i] = s;
        }
        i = 0;
        for(char s:subString.toCharArray()){
            i++;
            T[i] = s;
        }
        //得到NEXT数组
        int[] next = getNext(T);

        i=1;
        int j =1;
        while(i<=S[0] && j<=T[0]){
            if(S[i] == T[j] || j==0){
                i++;
                j++;
            }else{
                j = next[j];
            }
        }

        if(j > T[0]){
            return i - T[0];
        }
        return -1;
    }

    public static void main(String[] args) {
        String mainString = "cfrababaaaba";
        String subString = "ababaaaba";

        int index = kmp_search(mainString, subString);
        System.out.println(index);

    }

}

输出:4,索引是从1开始的。

 

在上面的代码中,abaaaba字符串会生成一个数长度为8的next数组,其中第一位为字符串的长度。这个是因为当时学习KMP算法时看的教程是用C语言实现的,所以第一版实现也是按照这个来的,下面我们用JAVA的思想来实现:

package recursion;

/**
 * KMP算法
 **/
public class Kmp {

    public static int[] getNext(char[] T){

        int j=-1; //前继
        int i=0; //后继
        int[] next = new int[T.length];
        //next数组第一个元素永远为-1
        next[0] = -1;

        while(i<T.length-1){
            if(j == -1 || T[i] == T[j]){
                i++;
                j++;
                if(T[i] != T[j]){
                    next[i] = j;
                }else{
                    next[i] = next[j];
                }
            }else{
                //j 回溯
                j = next[j];
            }
        }
        return next;
    }

    public static int kmp_search(String a, String b){
        char[] S = a.toCharArray();
        char[] T = b.toCharArray();


        //得到next数组
        int[] next = getNext(T);
        int i=0, j=0;

        while(i<S.length && j<T.length){
            if(j == -1 || S[i] == T[j]){
                i++;
                j++;
            }else{
                j = next[j];
            }
        }

        if (j >= T.length){
            return i - T.length;
        }

        return -1;
    }

    public static void main(String[] args) {
        int index = kmp_search("cfrababaaaba", "ababaaaba");
        System.out.println(index);
    }


}

结果:3,索引是从0开始的

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值