KMP算法,你想知道的都在这里!
简洁
我相信很多人都听说过KMP算法(PS:在上数据结构的时候,这个算法自始至终都没想明白)
大家也知道KMP算法是用来寻找目标子串的算法,但是都没有真正搞懂KMP。之前,我也是如此,我疑惑的有:
- Next数组中的值是如何定下来的?
- 得到Next数组以后,又是如何遍历的?
希望这篇文章能对你们有所帮助!
视频推荐
KMP这种算法,单单靠看文章,还是很难弄懂的,结合图像,以及视频的帮助会更容易弄懂。这里我推荐一个视频:KMP算法
个人也是通过这个视频,恍然大悟的。这里还是非常感谢这位作者的分享。
个人总结
通过上述视频,我想大家应该都有一个大概的了解了。该算法我将它划分为两个部分:
- 求Next数组
- 匹配字符串
我将分这两个部分进行细致讲解
第一部分
求Next数组是KMP算法的重点,也是难点!想搞懂这部分一定要看视频!一定要看视频!一定要看视频!我觉得上述的视频,将这部分说的很清楚了。这里做一个总结:(视频里将目标子串的第i号位置映射到Next指针的第i+1号位置。我这里根据程序员的习惯,将目标子串的第i号位置映射到Next指针的第i号位置)
我将Next[i]做一下定义:
/*Next[i]表示:
* 如果(substr.charAt(i) != str.charAt(j)),这时候,将i = Next[i],再进行字符串匹配。
*/
这种表达虽然不严谨,但是我感觉比较直观hhhh。也即:如果目标子串第i个的值与匹配串第j的值不一致的时候,将目标子串向右滑动,滑动到i = Next[i]。
Next[i]值的定义:
/*Next[i]的值为:
* 第0位为头的字符串s1,与第i-1为尾的字符串中s2,寻找他们的最长真子串。
* 真子串:这个真子串,就是s1的长度要小于i-1。因为这两个子串如果是相同的,就没有意义了
*/
上面这两个定义值得细品,这也是KMP的精髓,也正是Next数组,KMP算法才能更加高效!
其中需要注意的点是:Next[0] = 0,Next[1] = 0,因为从第2个开始,s1和s2才有意义。
看完上述定义,我将求Next数组的函数实现出来。注:该函数求Next数组时间复杂度较高,因为是最原始的思路,大家可以想想有什么简化的思路,可以在评论区留言,之后我有时间进行改进
/**
* 该函数是为了,根据目标子串subStr,求解该子串的Next数
* @param 目标子串substr
* @return subStr的Next数组
*/
static int[] CalculateNext(String substr){
//init
int[] Next = new int[substr.length()];
//求解Next[i]
for(int i = 2; i < substr.length(); i++){
//第0位为头的l字符串,与第i-1为尾的r字符串
int left = 0; int right = i - 1;
String l = Character.toString(substr.charAt(left));
String r = Character.toString(substr.charAt(right));
int maxLen = 0;
//当l与r均为真子串的时候
while(left < i - 1){
//如果两个字符串相同,说明这是目前最长的公共子串
if(l.equals(r)) maxLen = l.length();
left++;
right--;
//继续扩大搜索范围
l = l + Character.toString(substr.charAt(left));
r = Character.toString(substr.charAt(right)) + r;
}
//最终的maxLen即为Next[i]的值
Next[i] = maxLen;
}
return Next;
}
第二部分
这个部分就简单很多了,只要注意一点小细节,整体思路非常清晰直观:
在保证目标子串与匹配串匹配的过程中,不会越界的情况下:进行目标子串的滑动操作
当subStr.charAt(i) == str.charAt(j)的时候,i与j同时往右移动即可,当完全匹配的时候,就返回
当subStr.charAt(i) != str.charAt(j)的时候,i = Next[i]即可。
这里j需要注意一个细节,如果i == 0,需要j往右移一位,因为第一位都不匹配,前面就再也没有能匹配的字符串了。
/**
* 该函数用于查看目标子串在匹配串中第一次出现的位置
* @param 目标子串subStr
* @param 匹配串str
* @param Next数组
* @return str中,第一次出现subStr的位置
*/
static int findPosition(String subStr,String str,int[] Next){
//初始化两个字符串的指针
int i = 0;
int j = 0;
//保证目标子串与匹配串匹配的过程中,不会越界
while(j + subStr.length() - i <= str.length()){
//当匹配的时候,i与j同时往右移
if(subStr.charAt(i) == str.charAt(j)){
i++;j++;
//当完全匹配的时候,返回
if(i == subStr.length()) return j - subStr.length();
}
//不匹配的时候,匹配串指针j只有在i = 0的时候,才右移动。
else {
if(i == 0) j++;
//i值都需要更新
i = Next[i];
}
}
return -1;
}
总结
这里主要探讨的是Next数组,这个是KMP算法的核心!以前考试都是考Next数组的求解,可见Next数组的重要性。
KMP算法,你想知道的都在这里!的更多相关文章
- 扩展KMP算法
一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...
- [Algorithm] 字符串匹配算法——KMP算法
1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...
- Java数据结构之字符串模式匹配算法---KMP算法
本文主要的思路都是参考http://kb.cnblogs.com/page/176818/ 如有冒犯请告知,多谢. 一.KMP算法 KMP算法可以在O(n+m)的时间数量级上完成串的模式匹配操作,其基 ...
- KMP算法解析(转自图灵社区)
KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...
- 字符串匹配的KMP算法
~~~摘录 来源:阮一峰~~~ 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”? 许 ...
- 深入理解KMP算法
前言:本人最近在看<大话数据结构>字符串模式匹配算法的内容,但是看得很迷糊,这本书中这块的内容感觉基本是严蔚敏<数据结构>的一个翻版,此书中给出的代码实现确实非常精炼,但是个人 ...
- 初探KMP算法
数据结构上老师也没讲这个,平常ACM比赛时我也没怎么理解,只是背会了代码--前天在博客园上看见了一篇介绍KMP的,不经意间就勾起了我的回忆,写下来吧,记得更牢. 一.理论准备 ...
- KMP算法 --- 深入理解next数组
在KMP算法中有个数组,叫做前缀数组,也有的叫next数组. 每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符. 当然它描述的也是子串的对称程度,程度越高,值 ...
- KMP算法详解 --- 彻头彻尾理解KMP算法
前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k. 但是问题在于如何求出这个最大前后缀长度呢? 我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破, 后来翻看 ...
随机推荐
- Java-eclipse导入jar包
Java-eclipse导入jar包 方法一:基本步骤式 右键项目属性,选择Property,在弹出的对话框左侧列表中选择Java Build Path,如下图所示:选择Add External JA ...
- 通过模拟数据,使用js在前端实现模糊查询下拉框功能实例教程
所谓模糊查询就是通过关键字在数据中匹配到包含关键字的数据,而得出的查询结果.本实例教程讲解在前端文本框输入关键字,显示匹配的数据列表功能. 首先得准备一个文本框和显示数据列表的div元素,html代码 ...
- NodeMCU学习笔记
NodeMCU学习笔记 引脚连通 引脚 连通 D3 FLASH按键 D0 模组上的LED D4 芯片的LED FLASH按键 D3引脚已经与开发板上的FLASH按键开关连接 我们可以通过NodeMCU ...
- G - 跑跑卡丁车
跑跑卡丁车是时下一款流行的网络休闲游戏,你可以在这虚拟的世界里体验驾驶的乐趣.这款游戏的特别之处是你可以通过漂移来获得一种加速卡,用这种加速卡可以在有限的时间里提高你的速度.为了使问题简单化,我们假设 ...
- 动态规划TG.lv(1) (洛谷提高历练地)
动态规划TG.lv(1) P1005 矩阵取数游戏 分析:每行不超过80个数字,直接区间DP即可,\(dp[i][j]\)表示区间\([i,j]\)之间取数可以得到的答案,每次向右或者向左扩展即可.但 ...
- 【poj 2976】Dropping tests(算法效率--01分数规划 模版题+二分){附【转】01分数规划问题}
P.S.又是一个抽时间学了2个小时的新东西......讲解在上半部分,题解在下半部分. 先说一下转的原文:http://www.cnblogs.com/perseawe/archive/2012/05 ...
- 迪杰斯特拉+拆点 Deliver the Cake - HDU 6805
题意: t组输入,给你n个点m条边.你需要输出从s点到t点的最短距离,然后是m条边,每条边输入信息为: a,b,c 表示从a点到b点的一个无向边长度为c 每一个点会有一个属性L.R或M 如果a和b一个 ...
- 数据可视化 -- Python
前提条件: 熟悉认知新的编程工具(jupyter notebook) 1.安装:采用pip的方式来安装Jupyter.输入安装命令pip install jupyter即可: 2.启动:安装完成后,我 ...
- 如何使用Gephi工具进行可视化复杂网络图
在Gephi安装官网中也介绍了一些如何使用该工具的方法,我将根据自己的数据和可视化的图片进行介绍 第一步:整理数据格式,我的数据是.csv格式的(.xlsx,.xls等等) 数据第一行第一列必须是相同 ...
- Redis Cluster 分布式集群(下)
Redis Cluster 搭建(工具) 环境准备 节点 IP 端口 节点① 172.16.1.121 6379,6380 节点② 172.16.1.122 6379,6380 节点③ 172.16. ...