KMP

KMP算法:判断两个字符串的包含关系

一、知识储备

子串/子数组 : 元素之间必须相邻且连续
子序列: 元素之间相对前后顺序不变,无须相邻,
两子串的包含问题:
str1是否包含str2 若包含,则从str1的哪个字符开始
str1 abc123def
str2 123def

kmp相关概念

前缀子串: 从字符串首位到该字符的前一位置(不包括该位置)
后缀子串 : 从字符串第二位到该字符的前一位置
字符串中任意字符的匹配程度:该字符前缀子串与后缀子串相等的最大长度
字符串abcabcd
d的最长前缀子串为abcab
d的最长后缀子串为bcabc
next[] 表示每个位置的最长前缀和最长后缀的匹配程度
例子:

字符串ababcd
next数组-100123

二、暴力方法

遍历str1每个位置,以该位置为起始的子串与str2匹配,时间复杂度O(m*n) 其中m>=n

三、KMP加速匹配过程

3.1流程图
  1. str1[i,X-1]与str2[0,Y-1]相等,str1[X]!=str2[Y]

str1[i,X-1]与str2[0,Y-1]相等,str1[X]!=str2[Y]
2. 根据str2[Y]的next值,判断是否小于0
若小于0,说明Y是str2的首字符,与str1[X]不等,则j==X+1,str1从j位置与str2重新匹配
否则:找到str1中新的起始字符,记为j,此时判断str2[Z]==str1[X]
若相等,则继续X++,Z++,继续比较
若不等,则把Z当做Y,重复步骤2

跳跃式

例子

abcabct
abcabca
在这里插入图片描述

3.2kmp实质: 确定[i,j)位置上没有匹配str2的字符,可以通过反证法证明,实现了一次比较,跨越了str1上的k个字符

在这里插入图片描述

3.3求next数组

数学归纳法,有点类似DP
如下图,
步骤一:想求字符a的前缀后缀匹配最大值,只需知道其前一字符b的next值,
若next值<=0,则next[aIndex]=0
否则比较str2[x] == b
若相等,则next[aIndex] = next[bIndex]+1
在这里插入图片描述
若不相等,则把str2[c]当成步骤一中的b,重复这一过程,

在这里插入图片描述

在这里插入图片描述

/**
 * Created by huajianJin on 2019/10/11.
 */
public class KMP {

    static int[] getNextArray(String s) {
        if(s.length()< 0) {
            return new int[] {-1};
        }
        char[] chs = s.toCharArray();
        int[] next = new int[s.length()];
        next[0] = -1;
        next[1] = 0;
        int pos = 2;
        int lastCharNext = 0; // cn = next[pos-1]
        while(pos < next.length) {
            if(chs[pos - 1] == chs[lastCharNext]) {
                next[pos++] = ++lastCharNext; // cn = next[pos-1]
            } else if(lastCharNext > 0){
                lastCharNext = next[lastCharNext];
            } else { //  chs[0] != chs[pos-1] && lastCharNext <= 0 
                next[pos++] = 0;
            }
        }
        return next;
    }
    static int getIndex(String s1,String s2) {
        char[] chs1 = s1.toCharArray();
        char[] chs2 = s2.toCharArray();
        int r1 = 0;
        int r2 = 0;
        int next[] = getNextArray(s2);
        while(r1<s1.length() && r2<s2.length()) {
            if(chs1[r1]==chs2[r2]) {
                r1++;
                r2++;
            } else {
                if(next[r2] > 0) {
                    r2 = next[r2];
                } else { // r2 = 0,
                    r1++;
                }
            }
        }
        return r2 == chs2.length ? r1-r2 : -1;
    }

    public static void main(String[] args) {
        String s1 = "abcafbca";
        String s2 = "fb";
        int res = getIndex(s1,s2);
        System.out.println(res);
    }
}

四、总结

获得next数组的时间复杂度O(M),整体时间复杂度O(N)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值