一.KMP算法的作用
举个例子,excel表格大家都用过吧,在表格内按下“Ctrl+F”可以弹出“查找和替换”功能,输入我们想要查找的关键字,系统就会帮我们定位到具体的位置,没有找到就上报具体的错误信息,KMP算法的作用就和excel表格的“查找”功能一样,帮你从一堆字符串中找到你想要的字符。
当然你也可以参考力扣的这题:
二.KM怕算法需要准备什么?
- 文本:也就是你准备在里面找你想要的字符串的文本,在C/C++中一般用string或者char数组来保存,所以其他文章一般称呼为“文本串”
- 关键字:也就是你想在文本里面找到的那串字符,在C/C++中一般用string或者char数组来保存,所以其他文章一般称呼为“模式串”
- Next函数:该函数是算法的核心部分,函数根据模式串的内容计算出一堆数据,生成一个数组,叫做next数组,进行文本匹配时主要就是用到这个数组里面的数据来确定移动的位置。
三.KMP算法的匹配过程
我们按照以下的例子进行说明:
我们要在文本串中找到模式串所在的位置,需要用到经过next函数计算出来的next数组:
至于这个数组是怎么算出来的先暂时别管,下面会有详细的说明,我们先来看一下这个数组里面保存的数据是什么用的:
可以看见,next数组其实存储的是模式串数组的下标,用于把移动到特定位置的。我们开始进行文本串匹配,首先逐个逐个进行对比:
第一个字符串匹配成功,我们再来匹配下一个字符串:
当出现匹配错误的时候,我们之前计算出来的next数组就可以派上用场了,首先第一步,找到模式串对应位置下next数组相同位置里所存储的数值是多少,在本例子中,是模式串第1个位置不匹配,所以就找next数组中下标为1中存储的值:
按照前面可以知道,next数组存储的是模式串数组的下标,当前next[1]存储的值为0,所以将模式串[0]移动到当前模式串所指的位置,其他数组也跟着一起整体移动:
整体移动完成之后,继续对比当前两个位置的字符串是否匹配,不匹配就进行相应的操作:
发现不匹配之后,查找next[0],发现值为-1,但是模式串数组下标最低只有0,哪来的-1呀?其实0的前面就是-1,你也可以理解为指向空NULL:
移动完成之后再次进行对比,因为模式串当前所指的值为空,没有东西可以对比了,所以俩箭头集体往右移动一位,继续进行对比,其余的操作也就是重复上面这些操作而已:
一直移动到匹配不上的位置,启动对应位置的next数组,找到对应的位置:
紧接着移动到对应的位置:
然后再进行两个字符串对比,相同就下一个,不同就重复执行上面的步骤,直到匹配到最后一个字符:
至此,KMP算法就完成它的使命,返回对应的模式串在文本串中的位置即可。
四.next数组的计算
KMP算法的核心是next数组里面所保存的数值,其代表了当模式串与文本串不匹配时模式串需要移动的位置,该数值也有一个名称,叫做最大公共前后缀长度。 我们以就拿以下的模式串来说明next数组是怎么被计算出来的:
在正式开始计算之前,先来补充一些知识:
- 前缀:除了最后一位,其他都是前缀
2.后缀:除了第一位,其他都是后缀
3.前后缀共同的部分:就是前后缀相同的部分
4.最大公共前后缀长度:就是前后缀共同部分有多长
知识补充完毕,又来以上的知识,我们就可以开始计算了,我们还是拿上面的模式串作为例子:
第一步,将模式串的所有排列组合都列出来
第二步:计算每个组合的公共前后缀
第三步:算出各个前后缀公共长度
第四步:将计算出来的数值存入next数组中
有些文章到此就结束了,将以上作为next数组的值,这样的话移动时是按照箭头的前一位的数值进行移动,比如当前箭头指向next[4],那么移动的时候是按照next[3]=1这个位置里面的数值进行移动的,所以也有些文章将next数组整体往右移动一位,再在第一位不上数值-1,这样移动时就直接看当前箭头指向的数值即可: