KMP算法
介绍
没有了解暴力匹配算法的可以先看看暴力匹配算法比较简单点击可以传送
kmp算法跟暴力匹配算法目的相同,都是解决类似于字符串匹配这样的问题的,但是kmp算法不同与暴力算法的是,暴力匹配算法时一次匹配不成功就回溯到上次匹配的下一个位置重新匹配,但是kmp算法可以根据需要匹配的子字符串前缀和后缀生成一个next数组,当匹配不成功时根据next数组里相对应的值,决定继续匹配的位置。
举个例子:如果子串是 AB…AB…。如果匹配失败了,就把前面的AB直接挪到后面AB的位置继续匹配。
next数组
next数组的作用是告诉我们在匹配不成功时,子串应该从哪个位置继续匹配。而不是(暴力匹配)主串回到上次匹配的第二个,子串回到第一个去继续匹配。
前缀后缀
图解(来自参考资料)
根据上图得到这样一个表
表的作用就是,如果当前字符是最后一个字符时,子串所拥有的相同前后缀的长度。
因为我们next是在匹配不成功时再去根据next的值去找到对应位置,那当前的数据就是已经匹配不成功了,所以忽略当前数据。因此我们的表的数据都要往前推一位,第一个值赋值0。
代码实现一下(求next数组)
// 先获得一个字符串的部分匹配表
// 把子串穿过来
public static int[] kmpNext(String dest){
// 定义next数组
int[] next = new int[dest.length()];
// 第一个一定是0
next[0] = 0;
for (int i = 1 ,j = 0; i < dest.length(); i++) {
// 如果不相等
// 当dest.charAt(i) != dest.charAt(j)
//我们需要从next[j - 1]获取新的j
// 直到我们发现有 dest.charAt(i) ==
//dest.charAt(j)成立才能退出
// kmp核心
while (j > 0 && dest.charAt(i) !=
dest.charAt(j)){
j = next[j - 1];
}
// 如果相等j++ 并保存
if (dest.charAt(i) == dest.charAt(j)){
j++;
}
next[i] = j;
}
return next;
}
代码再实现一下kmp
// 传入两个字符串 还有匹配需要的next数组
public static int kmpSearch(String str1 ,
String str2 , int[] next){
// 0:遍历主串
for (int i = 0,j = 0; i < str1.length(); i++) {
// 如果匹配不成功而且已经匹配了大于0个的话
while (j > 0 && str1.charAt(i) !=
str2.charAt(j)){
// 从表中取出对应的位置,子串的这个位置
// 继续匹配
j = next[j - 1];
}
// 1:先看这里如果都匹配成功
if (str1.charAt(i) == str2.charAt(j)){
j++;
}
//2: 并且匹配完成的话上传匹配的第一个数据的位置
if (j == str2.length()){
return i - j + 1;
}
}
return -1;
}
总结
我觉得kmp的算法就是不想跟暴力算法一样,匹配失败就回到上一次匹配的后一位继续。 kmp就是会找备胎,我想好了,不管再哪里失败被抛弃,我都有接盘侠接着。他的序号是next[某一个]。当然了找备胎不提倡哈。
参考资料
一键传送
https://blog.csdn.net/yyzsir/article/details/89462339
秃头萌新一枚 写的不是很好,多多包涵。