【算法】KMP
@
一. 暴力匹配
字符串匹配的最直接的方法就是暴力匹配,而KMP算法也是基于暴力算法进行改进。暴力匹配的思想如下:
- 对于文本串T和模式串P,从模式串P的第 0 号位置、文本串第 \(i_0\) 号位置开始逐一比对;
- 比对到中间某个时刻,若\(T[i ] == P[j]\),则比对继续进行,\(i++, j++\)
- 如果比对失败,则从模式串第0位和文本串的第\(i_0 + 1\)位继续进行

但是\(T[i_0 , i)\)和\(P[0, j)\)比对成功意味着\(T[i_0 , i)\)和\(P[0, j)\)完全相同的,掌握了\(P[0, j)\)那么也就意味着掌握了\(T[i_0 , i)\),下一轮的比对方案完全可以提前预知。
例1

在图中的比对过程中,主串中的 x 和模式串中的 y 失配,根据模式串中 y 以前的内容可以获知主串对应部分的内容。如果在下一步的比对过程中直接将主串中的 x 和模式串中的 e 进行比对,可以省去 6 次比对
二.KMP的基本思想
在对暴力破解的算法的分析中发现,对比在某个位置失败意味着在这之前的比对完全成功,主串中失配字符前的一段内容已经完全获知。利用这一点,对暴力算法可以进行两个方面的优化:
- 避免主串的回溯。暴力匹配当比对失败后,文本串的第\(i_0 + 1\)位、\(i_0 + 2\)位、……、\(i-1\)位的对比结果完全可以推导出来,没有必要再进行比对尝试;
- 模式串快速移动。基于和上面相同的原因,模式串的新的比对位置不需要从 0 开始。如例一中的模式串,字符y和字符e的前面都包含了"abc"这一部分,因此y前面的部分能和主串匹配成功,那么e前面的也一定能匹配成功。
因此对于模式串中的每个位置 j ,都能提前找到一个替代位置。
例2

模式串"abababca",对字符c而言,2号位的 a 和4号位的 a 都是能够在字符 c 发生失配时的一个可选择的位置
在诸多可选的继任位置中,位置下标越大,意味着已经成功匹配的长度越长,剩下需要比对的位置也就越少,因此 j 的继任位置\(next[j]\)定义为:
\]
通常定义\(next[0] = -1\)或者\(next[1] = 0\)(当字符串的下标从1开始时),这种规定是假想在模式串的起始位置的前一个有一个通配哨兵。
三.next[]的求法
1. 暴力求解
根据\(next[j]\)的定义,从逐一枚举字符P[j]的真前缀和真后缀,找出相等的真前缀和真后缀的长度,取长度的最大值即为\(next[j]\)
2. 递推求解
假设已经求得\(next[0, ... , j]\),递推求解\(next[j + 1]\)
\(next[j]\)已知意味着\(P[0, 1, ..., next[j] - 1]\)和\(P[j - next[j], ... , j - 1]\)是相等的,并且这个相等的部分是最大的,求取\(next[j + 1]\)时,只需要考察\(P[next[j]] == P[j]\)是否成立。如果成立,\(next[j + 1] = next[j] +1\) ,如果不成立,再考察\(P[next[next[j]]] == P[j]\)是否成立,依次类推,最终会收敛于\(next[0] + 1 = 0\)

插图来自视频
void buildNext(string str, int nt[]){
int len = str.size();
nt[0] = -1;
int t = nt[0], j = 0;
while(j < len - 1){
if(t < 0 || str[j] == str[t]){
nt[++j] = ++t;
}else{
t = nt[t];
}
}
}
四.KMP算法
在求解了next数组之后,kmp算法变得非常简单了。
int kmp(string str1, string str2){
int nt[str2.size()];
buildNext(str2, nt);//构建next表
int i = 0, j = 0;
while(i < str1.size() && j < str2.size()){//逐步比对
if(j < 0 || str1[i] == str2[j]){//比对成功时,前进一位,j < 0表示和通配符比对成功
i++; j++;
}else{//对比失败,找到新的位置比对
j = nt[j];
}
}
return i - j;
}
【算法】KMP的更多相关文章
- [每天默写一个算法]KMP
[每天默写一个算法]KMP 作业要求:默写String的KMP算法. KMP是经典的字符串匹配算法.复杂度为O(n+m) public static class StringKMP { /// < ...
- 数据结构与算法--KMP算法查找子字符串
数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...
- 经典算法 KMP算法详解
内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...
- 笔记-算法-KMP算法
笔记-算法-KMP算法 1. KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...
- 值得花费一周研究的算法 -- KMP算法(indexOf)
KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...
- 算法-KMP串匹配
字符串匹配 http://www.cnblogs.com/jingmoxukong/p/4343770.html 模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串 ...
- [C++] [算法] KMP算法
KMP串匹配算法是一个经典的算法. 传统BF算法是传统的字符串匹配算法.很好理解.叶实现.但时间复杂度太高. 本文将从字符串模式字符串被称为.为了匹配字符串被称为主弦. KMP配时能够少移动从串的位置 ...
- [算法] kmp实现
字符串查找是经典场景,也是面试中最常见的一道题. 说来惭愧,毕业3年了,才明白了kmp算法的实现,以前一直以为这类算法是基础,工作中中不会碰到[也的确没有碰到过...] 但是,对这些基本算法结构的理解 ...
- 程序员必会算法-KMP算法
KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串. 下面通过一个例子,为大家仔细说明KMP算法的使用和思路: 问题: 在字符串“DEA ...
- 算法 kmp算法
kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...
随机推荐
- 对ORM的理解
1. 在面试中可能会问到这个问题,什么是ORM? ORM是对象关系映射(Object Relational Mapping),简称ORM,或O/RM,或O/R mapping,是一种程序技术. 白话理 ...
- ElasticSearch 使用
一.索引操作 --------------------------------- 创建索引(PUT) PUT /索引名 curl -X PUT http://10.20.20.214:9200/sho ...
- tomcat Address already in use: JVM_Bind
运行多个tomcat时,出现tomcat Address already in use: JVM_Bind这个错误,可以按照如下方式解决: 修改F:\tomcat20111101\apache-tom ...
- MySQL查询列必须和group by字段一致吗?
@ 目录 场景:查询各部门薪水最高的员工. 方法一: 方法二: MySQL group by是如何决定哪一条数据留下的? 分组前的数据: 那么target list和group by column不匹 ...
- 五、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊天APP,支持各类消息收发,音视频通话,附vue实现源码(已开源)-聊天输入框的实现
会话好友列表的实现 1.项目引言 2.腾讯云后台配置TXIM 3.配置项目并实现IM登录 4.会话好友列表的实现 5.聊天输入框的实现 6.聊天界面容器的实现 7.聊天消息项的实现 8.聊天输入框扩展 ...
- MySQL查找数据中相同的数据,并进行删除
查找表中多余的重复记录,重复记录是根据某个字段来判断 select * from 表名 where 字段 in (select 字段 from 表名 group by 字段 having count( ...
- F. Geometrical Progression
http://codeforces.com/problemset/problem/758/F F. Geometrical Progression time limit per test 4 seco ...
- 第二十个知识点:Merkle-Damgaard hash函数如何构造
第二十个知识点:Merkle-Damgaard hash函数如何构造 这里讲的是MD变换,MD变换的全称为Merkle-Damgaard变换.我们平时接触的hash函数都是先构造出一个防碰撞的压缩函数 ...
- 「算法笔记」Min_25 筛
戳 这里(加了密码).虽然写的可能还算清楚,但还是不公开了吧 QwQ. 真的想看的 私信可能会考虑给密码 qwq.就放个板子: //LOJ 6053 简单的函数 f(p^c)=p xor c #inc ...
- Histogram Processing
目录 HISTOGRAM EQUALIZATION 代码示例 HISTOGRAM MATCHING (SPECIFICATION) 其它 Gonzalez R. C. and Woods R. E. ...