KMP算法简解

  1. 与暴力匹配最显著的区别是,在进行串的匹配时,主串P,模式串为S,某个字符不匹配的时候,i不变,j=next[j],从而避免的i指针的回溯,节省了时间开销
  2. 对于next数组:当模式串中第j个字符匹配失败时,由前1~j-1个字符组成的串记为S,则next[j] = S 的最长相等前后子串的长度 + 1
    图解如下:
    KMP图解1
    挡第j个字符匹配失时,我们尝试将模式串后移,那么,移动多少呢?这时候,我们考虑前后缀的概念,如图,j=7时匹配失败,我们把前1~(k-1)个字符看做串S,实际上给,我们要做的,就是把最长前缀移动至最长后缀,此时,i不变,j=next[j]=S的最长前后缀长度+1=5
    KMP图解2
  3. 手算next数组
    手酸next数组
    我们知道:
    next[1] = 0
    next[2] = 1

KMP算法原理很容易理解,下面看一下Java实现:

/**
 * @program: algorithm_learn
 * @description: KMP算法实现
 * @author: Mr.Luo
 * @create: 2020-06-08 16:45
 */
public class Kmp_imp {
    public static void main(String[] args) {
        Kmp_imp kmp = new Kmp_imp();
        String a = "abababcdef";
        String b = "abcd";
        int[] next = kmp.get_next(b.toCharArray());
        for(int i = 0; i < next.length; i++){
            System.out.println(b.charAt(i)+"    "+next[i]);
        }
        int res = kmp.Kmp(a, b);
        System.out.println(res);
    }

    public int[] get_next(char[] T){
        int pLen = T.length;
        int[] next = new int[pLen];
        int i = 0;
        int j = -1;
        next[0] = -1;
        while (i < T.length-1){//注意i < T.length-1,因为++i之后才开始算next[i]
            if (j==-1 || T[i]==T[j]){
            ++i;
            ++j;
            next[i] = j;
            }else {
                j=next[j];
            }
        }

        return next;

    }

    public int Kmp(String source, String pattern){
        int i = 0, j = 0;
        char[] src = source.toCharArray();
        char[] ptn = pattern.toCharArray();
        int sLen = src.length;
        int pLen = ptn.length;
        int[] next = get_next(ptn);

        while (i < sLen && j < pLen){
            if (j == -1 || src[i] == ptn[j]){
                ++i;
                ++j;
            }else {
                j = next[j];
            }
        }
        if (j == pLen){
            return i - j;
        }

        return -1;
    }

}

输出结果:

a -1
b 0
c 0
d 0
4

表示从主串下标为4开始匹配
注意:代码中,下标均从0开始,而分析中的j从1开始,即代码中的next[j]相当于分析中,j和next[j]同步-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值