二更: 理解学会以后,感觉写的好垃圾,翻翻最下面资料吧还不错.
kmp算法
可以说目前耗时较长,比较晦涩难以吸收的算法,介绍我就不多说了
文中是自己的学习过程中资料合集
可以翻最最后各种资料进行资料套娃.
说说重点区别
若是没有对照<<大话数据结构>>,可看一眼第4.5点
简单说: 书本和网上公式不同造成的求法不同,从而结果不同,最后配套使用,最好理解到家.
这个区别在代码前面,才能好好敲代码,毕竟不可能只看一本书就能看懂KMP,然后查阅资料至少对照了五组算法资料,终于有帖子附资料,发现其中的不同
-
<大话数据结构> 中的算法我对照书籍在使用上有一点点区别.书中
next
数组声明了255
长度(p114倒数第四行),若是new int[str.toCharArray().length]
长度的话,就会溢出,你可以+1长度 -
书中的算出来next[]所有基础都是j=1的情况下.故第一个例子中
abcdex
,对照了j=1
的next[1]=0
…next[2]=1
…的数组,其实真实next[7]={0,0,1,1,1,1,1}
注意第一个next[0]
,而往往网上资料,都会输出0 0 1 1 1 1 1
,造成结果感觉总是差一位,初学者不要怀疑自己.
-
在看视频1(<–这个1可以点)时,更能加深上面一点,<<大话数据结构>>子串(模式串)下标从1开始存的!!!,第0位没用到,所有的例子都是j=1开始,造成你从网上拿到资料,总感觉和书上对不上
-
接着上一点,还有一点对不上,数字都对不上呢.因为真的是公式不同
在KMP算法讲解(next数组求解中)使用的公式是:
而书中的资料公式是
这样同样的模式串算出来的结果是-1 0 0 0 0
和0 1 1 1 1 1
可以先区分出来你看的资料是多少,然后再说对不对. -
不算区别,算强调吧.注意知识点,就是前缀后缀最长公共元素长度和next数组 不一样.导致也浪费了一些时间
求next[]代码
因为搜索了理解前期搜索了很多资料,在此集合一下next不同求法
我这里四种求法只是搬运工,配套使用 配套使用 配套使用
package com.company;
/**
* @Author: comfort
* @Date: 2020/8/5
*/
public class StringTest {
public static void main(String[] args) {
String source = "ABCDABD";
int[] ints;
System.out.println("暴力匹配O(m^3)前后缀");
ints = KMPArray(source);
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println("\n时间复杂度O(p*k)?");
ints = getNext5(source);
for (int anInt : ints) {
System.out.print(anInt+" ");
}
//这个没做出来,可能转JAVA哪里没对上算出来的不对
System.out.println("\n<<大话数据结构>>中算法,下标0 不计入");
ints = getNext3(source);
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println("\n 使用-1公式");
ints = getNext4(source);
for (int anInt : ints) {
System.out.print(anInt+" ");
}
}
/**
* KMP算法讲解(next数组求解)
* https://blog.youkuaiyun.com/qq_37174526/article/details/90141833
*/
public static int[] KMPArray(String lookup){
int length = lookup.length();
char[] chars = lookup.toCharArray();
int[] next = new int[chars.length];
next[0]=-1;
next[1]=0;
for (int i = 2; i<length; i++) {
//最长长度
int maxLen =i-1;
int len,j;
//从后缀查起来
for ( len = maxLen ; len >= 1; len--) {
//从前缀开始
for ( j = 0; j < len; j++) {
if (chars[j] != chars[j + i - len]) {
break;
}
}
if (j == len) {
next[i]=len;
break;
}
}
if (len < 1) {
next[i]=0;
}
}
return next;
}
/**
* 字符串匹配的KMP算法
* https://blog.youkuaiyun.com/qq_41730082/article/details/83350315
*/
public static int[] getNext5(String string) {
int len = string.length();
char[] str = string.toCharArray();
int[] next = new int[len];
next[0] = -1;
int k = -1;
//基础待查字符串的长度
for(int q=1; q<=len-1; q++)
{
//K+1从0开始,Ks初始化为-1的原因
//如果第K+1位与目前遍历这位相等,我们就继续往下走,不然就要向前回溯了
while(k>-1 && str[k+1]!=str[q])
{
//向前回溯
k = next[k];
}
//如果经过前面判断后的下一位与目前的这位相等,那么就将K推到K+1
if(str[k+1] == str[q])
{
k++;
}
//给予next[]数组赋予对应的值
next[q]=k;
}
return next;
}
/**
* KMP字符串模式匹配算法Java实现
* http://www.voidcn.com/article/p-uiblkjbk-bpu.html
*/
protected static int[] getNext4(String s) {
// 已知next[j] = k,利用递归的思想求出next[j+1]的值
// 如果已知next[j] = k,如何求出next[j+1]呢?具体算法如下:
// 1. 如果p[j] = p[k], 则next[j+1] = next[k] + 1;
// 2. 如果p[j] != p[k], 则令k=next[k],如果此时p[j]==p[k],则next[j+1]=k+1,
// 如果不相等,则继续递归前缀索引,令 k=next[k],继续判断,直至k=-1(即k=next[0])或者p[j]=p[k]为止
char[] p = s.toCharArray();
int pLen = p.length;
int[] next = new int[pLen];
int k = -1;
int j = 0;
// next数组中next[0]为-1
next[0] = -1;
while (j < pLen - 1) {
if (k == -1 || p[j] == p[k]) {
k++;
j++;
next[j] = k;
} else {
k = next[k];
}
}
return next;
}
/**
* <<大话数据结构>>中算法
* 总觉得哪里不对...
*/
public static int[] getNext3(String str) {
char[] chars = str.toCharArray();
//记得长度+1
int[] next = new int[chars.length+1];
int i=1;
int j=0;
next[1]=0;
while (i < chars.length) {
if (j == 0 || chars[i] == chars[j]) {
++j;
++i;
next[i]=j;
}else{
j = next[j];
}
}
return next;
}
}
当然输出也是不一样的
暴力匹配O(m^3)前后缀
-1 0 0 0 0 1 2
时间复杂度O(p*k)?
-1 -1 -1 -1 0 1 -1
<<大话数据结构>>中算法,下标0 不计入
//书中的转java失败,暂时不要使用.
0 0 1 1 1 1 2 1
使用-1公式
-1 0 0 0 0 1 2
看着都不一样,后续还有配合kmp算法一起食用,
我感觉答案应该还得+1,因为 KMP算法计算next函数值(教材版,超简单!) 看了这个视频
唉…书中的算法照着抄都没做出来,可能C和java哪里不一样,比较失败.希望大佬告诉我.
我自己用的KMP字符串模式匹配算法Java实现(这篇也是转载别人的.也可以进行资料套娃…)实现的,大家看着来一套.
关于这几个资料的翻阅或者翻阅资料的收获
- 读资料独立思考,理解晦涩,但是有收获零碎知识收获
- 其次看视频,结合资料零碎知识可以迅速组织成知识树(看视频恍然大悟.)
- 重在理解,还需巩固.最好默写.
参考资料
文章:
- 大概知道next数组怎么算和怎么回事:
数据结构与算法之美笔记: 字符串匹配 「BF 算法、RK 算法、BM 算法、KMP 算法」- 深入浅出,获取next[]从暴力遍历O(m^3)再次优化O(m)
KMP算法求解(next数组求解)- 逐步讲解数组一步步优化,增加在next数组上再次改进
KMP字符串模式匹配算法Java实现- 详细,最重要的文中引用了大量文献,可以引用套娃(滑稽)
从头到尾彻底理解KMP- 包含了拓展习题,先make一下.
字符串匹配的KMP算法视频:
- 大概知道next数组可以这么简单算出来,好像很简单样子:
KMP算法计算next函数值(教材版,超简单!)- 巨卜木曹,原来是这么来用的,但是-1和0那边以及计算欠缺点:
天勤公开课」KMP算法易懂版- 嗯,舒服了,介绍prm数组和next数组,补充了上一个视频中的-1和0,还有next数组生成过程中,前缀后缀在匹配中动画演示,最后还附加了c++和php的代码
【算法ABC × Manim】KMP算法 - 拒绝做暴力字符串匹配的受害者