![edddd58c8eb9308d7f1bb6f311274b5f.png](https://i-blog.csdnimg.cn/blog_migrate/7f7efa19b13ed31b05d83e35f6b3ecce.jpeg)
导语
本篇内容研究字符串匹配问题,首先介绍字符串匹配问题,引出Brute-Force算法及其优化方法,最后深入详解KMP算法。文章结构如下(全文阅读需要30分钟左右):
![bd985d7e901b345d8d4f80843d02fe02.png](https://i-blog.csdnimg.cn/blog_migrate/53416de5d164935b7ecd2edb14428bdc.jpeg)
字符串匹配问题
1字符串匹配问题是什么
"字符串A是否为字符串B的子串?如果是的话出现在B的哪些位置?"该问题就是字符串匹配问题,字符串A称为模式串,字符串B称为主串。
![614d80dafdf256a65aa1955da09f6a77.png](https://i-blog.csdnimg.cn/blog_migrate/21ae77128611d4d90d5e30357fa2e1cb.jpeg)
2应用
字符串匹配应用很广泛,比如你想在一篇文章中找到某个关键字所在的位置,或者是你想在一份名单中找到某个名字是否出现等等
Brute-Force算法
1算法核心思想
Brute-Force算法简称BF算法(并不是Boy Friend),算法的核心思想跟名字一样粗暴,如下所示:
![66213d4673b846617f80d390f0af57b3.gif](https://i-blog.csdnimg.cn/blog_migrate/6053867e50106477d0317f749838c687.gif)
2python代码实现
![ad11bb67bf1d837b60027cc82a251f90.png](https://i-blog.csdnimg.cn/blog_migrate/f13648bc2d4b3ba4174234326b7d9879.jpeg)
假设n为主串长度,m为模式串长度。每一轮字符串比较:最差的情况为模式串最后一个字与主串不同其他都相同(如模式串为AAB,主串对应部分为AAC),必须走完整个字符串才能得出结果,因此复杂度为O(m)。所有轮字符串比较:最差的情况是移动到最后一次比较才寻找得到,总共需要n-m+1次,主串通常比模式串长很多,故Brute-Force时间复杂度为O(nm)
3算法优化思路
最坏的情况:
![e29078c60b360242e013ecaf3b1709ea.gif](https://i-blog.csdnimg.cn/blog_migrate/ee98ef8d6079b7d0dd9268e21e6f79e5.gif)
两个字符串是否相同的比较很难优化,只能逐字比较。然而比较的趟数是可以减少的,因此尽可能减少比较的趟数是算法优化的方向,也是KMP算法的核心思想。那么,让我们开始KMP算法的讲解。
KMP算法详解
KMP算法于1977年被提出,全称 Knuth–Morris–Pratt 算法,包含了三位前辈名字,分别是:Donald Knuth(K), James H. Morris(M), Vaughan Pratt(P)01算法核心思想
如何减少匹配的趟数呢?其实在每一次匹配过程中,我们就能够判断后续几次匹配是否会成功,算法的核心就是每次匹配过程中推断出后续完全不可能匹配成功的匹配过程,从而减少比较的趟数,如图所示:
![eddea06d6fe3ac76ee17250bf69fa971.gif](https://i-blog.csdnimg.cn/blog_migrate/2f8aaee360912a1afd3742701f77e2f0.gif)
因此,第一次匹配过之后,就可以得出可以直接跳到第四趟再进行判断的结论了。因为第一次匹配的时候,前5个序列和主串相同,只需要对模式串进行分析,模式串出现了重复单元(即AB),在第一次匹配失败后就可以直接跳跃到出现重复单元的位置。
![eea6add8c78a0fbb3273df7e0a0178e7.png](https://i-blog.csdnimg.cn/blog_migrate/022e9f30f9b792f165e7bbe9599f0310.jpeg)
2next数组
next数组实质上就是找出模式串中前后字符重复出现的个数,为了能够跳跃不可能匹配的步骤。
next数组的定义为:next[i]表示模式串A[0]至A[i]这个字串,使得前k个字符等于后k个字符的最大值,特别的k不能取i+i,因为字串一共才i+1个字符,自己跟自己相等毫无意义。
![5ddbc06e95ae8e05cab4b89ccd1bfed1.gif](https://i-blog.csdnimg.cn/blog_migrate/a6147b6505c566059fadf3b9b126cbc1.gif)
最终得到next数组为:
![382b2167a9a96d06c7a5639c5f325aa6.png](https://i-blog.csdnimg.cn/blog_migrate/1bd31f4f3b708f2e762d5f620baf2f7f.jpeg)
如何确定在移动过程中需要跳过多少步呢?下图更直观的体现了跳跃的过程:
![be83bc4d656b1cc61dca78d62cf9e4a0.png](https://i-blog.csdnimg.cn/blog_migrate/22bfdda7f9393b65ec4eec5382608e41.jpeg)
对于上述红色部分的计算跳过长度的公式为跳过的趟数=匹配上字符串中间字符长度-重复字符串长度
![35e3b15a73fb30c41cc1b8e558e6b42d.png](https://i-blog.csdnimg.cn/blog_migrate/e122ee71d841d54cb3f604cbabb6cef9.jpeg)
跳过这些步骤后并非再从头开始匹配,而是从重复位置开始匹配:
![d2235fced0891f397c55bd9d4c80c372.png](https://i-blog.csdnimg.cn/blog_migrate/941f494229afb96dc5302009d7286fac.jpeg)
最终,我们不难得出如下结论:
![f1d3ca0dc028b056ae21c504f8dcf44f.png](https://i-blog.csdnimg.cn/blog_migrate/40433c5ffcdcf5c4fb30b096f9365ca3.jpeg)
3python代码实现
1.首先建立KMP对象,初始化参数:
![439d7c8105189a79cbc2ee97c2ba0e8c.png](https://i-blog.csdnimg.cn/blog_migrate/e32cd95bf84a47f76345bb7b6e20d176.png)
2.建立next数组:
第一种最简单的构建方案,时间复杂度为O(m平法):
![d267674f63f43ee25d23f9a00ab02271.png](https://i-blog.csdnimg.cn/blog_migrate/74be56cae3bd32d52932547a77567b6e.jpeg)
第二种构建方案,是一种递推的方式进行构建,时间复杂度为O(n+m):
考虑:如果next[0], next[1], ... next[x-1]均已知,那么如何求出 next[x] ?我们已经知道next[x-1],标记next[x-1]=temp,则可以讨论A[temp]和A[x]的值,分2种情况讨论:
第一种情况:A[temp]等于A[x],也就是说在前一个next结果上又多了一个字符串相同的长度,因此next[x]为next[x-1]+1
![66f80df4505e26b8f9fd598209652975.png](https://i-blog.csdnimg.cn/blog_migrate/79a157df606e9072eb2723171fe9dc01.jpeg)
第二种:当A[temp]和A[x]不相等的时候,我们需要缩小temp,把temp变成next[temp-1],直到A[temp]=A[x]为止。A[now]=A[x]时,就可以直接向右扩展了。
![92a79148950d0cd0b0d3b2491681705b.png](https://i-blog.csdnimg.cn/blog_migrate/b44e2be78c47bcbfab4f0daf346269e0.jpeg)
递推构建next数组代码如下:
![874f205878d409ffd153f38fc0ce7a5a.png](https://i-blog.csdnimg.cn/blog_migrate/8cbaf921ebc5e2f27fe0b19559ee466b.jpeg)
3.检索过程代码:
![c1b3d7bc98c3d3bdc18462d3f0362cce.png](https://i-blog.csdnimg.cn/blog_migrate/566fa6c6a7ff59f2a3e20e44228cfdec.jpeg)
4.测试代码:
![d928b3446ac3a8827d711bed6eb1f524.png](https://i-blog.csdnimg.cn/blog_migrate/6b7db1ff96942ecad19f2c1b9602bf94.jpeg)
作者原创,未经授权请勿转载
![07148e977921c4e2589b902b5cae2603.gif](https://i-blog.csdnimg.cn/blog_migrate/07f03b86c13637b7e724df795ddde69d.gif)