KMP算法java实现

关于KMP算法,网上很多资源,就不介绍了,建议不懂的看看数据结构这本书,很详细,或者参看下面说说java实现,(整个算法流程加代码实现花了快一天时间)
首先看看一般的算法,也就是网上说的暴力(蛮力)算法,它的时间复杂度为O(n*m) m为模式串的长度,n为主串的长度

package test03;
public class test05 {
    public static int volientMatch(String s, String p) {
        int slen = s.length();
        int plen = p.length();
        int i = 0, j = 0;
        char[] sarray = s.toCharArray();
        char[] parray = p.toCharArray();
        while (i < slen && j < plen) {
            //当前字符匹配成功,则i++,j++
            if (sarray[i] == parray[j]) {
                i++;
                j++;
            } else {
            //当前字符匹配不成功,则模式串的j置0,主串从目前模式串首字符对应的下一个主串字符开始继续匹配
            //也就是先把主串的i回溯到目前模式串的首字符所在的位置的下一个字符(i-j+1),接下来
            //把模式串的p[0]字符与主串的这个(i-j+1)处的字符比较
                i = i - (j - 1);
                j = 0;
            }
        }
        //匹配成功,返回模式串p在主串s中的位置,否则返回-1
        if (j == plen) {
            return i - j;
        } else {
            return -1;
        }
    }
    public static void main(String[] args) {
        String s="abcdasdff";
        String p="sdf";
        int index = volientMatch(s, p);
        System.out.println(index);
    }
}
package test03;

public class test06 {
    public static void main(String[] args) {
        String source="abcadefabdf";
        String pattern="abdg";
        int index = KmpSearch(source, pattern);
        System.out.println(index);
    }
    /**
     * 
    * @Title: KmpSearch 
    * @Description: KMP算法
    * @param @param s 主串
    * @param @param p 模式串
    * @param @return 模式串在主串的匹配位置
    * @return int 
    * @author Administrator
    * @date 2017-5-25
    * @throws
     */

    public static int KmpSearch(String s,String p){
        int i=0,j=0;
        char[] sarray = s.toCharArray();//把主串和模式串都转化为字符数组
        char[] parray = p.toCharArray();
        int slen=s.length();
        int plen=p.length();
        int[] next = getNext(p);//获取模式串的next数组
        while(i<slen&&j<plen){
            //如果j=-1或者当前字符匹配成功,则i++,j++
            if(j==-1||sarray[i]==parray[j]){//注意next数组中可以取到-1的值,表示为模式串的头部,
                j++;
                i++;
            }else{
            //如果j!=-1,且当前字符匹配失败,则令i不变,j=next[j]
                j=next[j];
            }
        }
        if(j==plen){
            return i-j;
        }else{
            return -1;
        }
    }
    /**
     * 
    * @Title: getNext 获取模式串的next数组
    * @Description: TODO
    * @param @param p
    * @param @return
    * @return int[]
    * @author Administrator
    * @date 2017-5-25
    * @throws
     */
    public static int [] getNext(String p){
        int plen=p.length();
        char[] parray = p.toCharArray();
        int [] next=new int [plen];
        next[0]=-1;
        int k=-1,j=0;
        /**
        首先要明白next[j]=k是什么意思,简单概述就是:当主串s和模式串p比较时,当s[i]!=p[j]时,
        (我们不采用蛮力法时)我们的主串s的s[i]字符接下来该和模式串的p[k]字符进行比较,即我们
        不再是像蛮力法那样,每次把模式串右移一个字符,再回溯到主串的下一个字符进行比较。采用KMP
        算法,我们不需要回溯主串,而是直接把模式串右移j-k(j-next[j])个位置,进行下次比较。
        也就是说当s[i]!=p[j]的时候,接下来我们让s[i]和p[k](p[next[j]])进行比较。
        那么我们我们应该怎么求解next数组呢?已知next[j]=k,我们可以采用递归的方式求next[j+1]的值
        注意next[j]=k意味着p[0]p[1]p[2]....p[k-1]=p[j-k]....p[j-1],=左右各有k个值
        所以当求next[j+1]的时候,就需要比较p[0]p[1]p[2]....p[k-1]p[k]=p[j-k]....p[j-1]p[j]
        又因为p[0]p[1]p[2]....p[k-1]=p[j-k]....p[j-1]相等,所以只需要比较p[k]和p[j]
        假如p[k]=p[j],则next[j+1]=k+1,
        假如p[k]!=p[j],令k=next[k],此时再比较p[j]与p[k],假如如果不相等,则继续递归前缀索引,
        令 k=next[k],继续判断,直至k=-1(即k=next[0])或者p[j]=p[k]为止。
         */

        while(j<plen-1){//对于数组next长度为plen所以当一个循环不满足条件时,j=plen-1,刚好是next数组的最后一个。
            if(k==-1||parray[j]==parray[k]){//因为不可能p[0]和p[-1]比较,所以用k==-1
                ++k;
                ++j;
                next[j]=k;//next[j+1]=k+1
            }else{
                k=next[k];
            }
        }
        return next;
    }
}

其中求next数组的时间复杂度为o(m)其中m为模式串的长度,匹配的时间复杂度为o(n),n为主串的长度,所以总的时间复杂度为o(m+n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值