【KMP】【字符串】KMP字符串匹配算法 学习笔记
一、简介
KMP是由Knuth、Morris和Prat发明的字符串匹配算法,它的时间复杂度是均摊\(O(n+m)\)。其实用Hash也可以做到线性,只不过Hash存在极其微小的难以避免的冲突。于是就有了KMP。
KMP算法用作模式串匹配,可以找到一个长为\(m\)的模式串在一个长为\(n\)的主串中出现的次数和位置。
二、朴素算法(\(O(nm)\))
实际上是枚举模式串在主串中出现的位置,然后一一比对,出现错误就停止,移动到下一位。连续匹配成功\(m\)次就说明模式串在主串中出现了。
其实\(O(nm)\)是一个比较宽的上界,随机数据远没有这么慢。不过给出主串S="aaaaaaaaaaa",模式串T="aaab",就得每次匹配到最后才知道挂掉了。那么我们既然已经知道这样会挂掉,为什么还要重复匹配呢?这就是KMP要解决的问题。
三、KMP算法
0.注意事项
KMP算法中,字符数组下标是从1开始而不是0,这样会比较方便,在匹配的时候直接调用nxt数组就不用-1了,而且很直观。
1.nxt数组(next)
nxt数组是KMP算法的核心。
nxt数组nxt[i]中存的是后缀字符与前缀字符相同的个数,且后缀字符不是前缀字符,也就是不能完全匹配自己。
对于ababcab而言,它的nxt数组是
| nxt[1] | nxt[2] | nxt[3] | nxt[4] | nxt[5] | nxt[6] | nxt[7] |
| a | ab | aba | abab | ababc | ababca | ababcab |
| 0 | 0 | 1 | 2 | 0 | 1 | 2 |
| 没有后缀与前缀相同 | 没有后缀与前缀相同 | 前缀"a"=后缀"a" |
前缀"ab"=后缀"ab" 注意不能完全匹配自己 |
没有后缀与前缀相同(失配直接=0) | 前缀"a"=后缀"a" | 前缀"ab"=后缀"ab" |
看上去很简单。但是它怎么求呢?当然,如果递推掌握的比较好,可以知道,如果T[i+1]==T[nxt[i]+1],那nxt[i+1]=nxt[i]+1。而失配了怎么办,是我们接下来要解决的问题。
2.nxt数组的作用
在上面我们提到了,KMP算法是减少了朴素算法的重复匹配,均摊下来每个字符只匹配了一次。在上面的表格中,我们看到了nxt数组处理出了模式串后缀与前缀匹配数。当我们用模式串匹配主串,在后缀失配时,在模式串里与后缀相同的就是我们预处理出的前缀了,因此我们只需要把模式串前缀挪到现在的位置来即可。这时我们会发现,中间可能跳过很多没有用,也就是安排匹配不上的状态,这就是KMP的优化。
3.nxt失配的求法
可以看出,求nxt数组,就是在用模式串匹配自己,且不匹配第一位。当我们发现T[i+1]与T[nxt[i]+1]失配时,比nxt[i]要次一点但是仍然与T[i]所在后缀相同的前缀就是nxt[nxt[i]]了。就是我们相当于退而求其次,“贪心地”按长度从大到小找一个最能匹配上后缀的前缀。
匹配不到的情况
比如说
ababababc
↑
如果匹配到第8+1位时失配了,这时就去找第nxt[8]+1位,(nxt[8]=6)也就是第6+1位。此时发现还是不行,继续找第nxt[6]+1位……直到找到nxt[1]=0,退出循环,再看看第一位是否匹配,如果匹配,nxt[9]=1,否则nxt[9]=0。
重新匹配到的情况
abcaba
↑
这里匹配到第5+1位发现失配,去找nxt[5]+1=2+1,仍然不行,但是nxt[2]=0了,此时退出循环,发现T[1]=T[6],所以nxt[6]=1。
其实情况还有很多很多种,这里只是列举了几种,想让nxt数组的求法变得更加形象一些。
四、KMP代码
#include<cstdio>
#include<cstring>
char s[1000100];
char t[1000100];
int nxt[1000100];
int f[1000100];
int main()
{
scanf("%s",s+1);
scanf("%s",t+1);
int n=strlen(s+1);
int m=strlen(t+1);
for(int i=2,j=0;i<=m;++i)
{
while(j&&t[i]!=t[j+1])
j=nxt[j];
if(t[j+1]==t[i])
++j;
nxt[i]=j;
}
for(int i=1,j=0;i<=n;++i)
{
while(j&&(j==m||s[i]!=t[j+1]))
j=nxt[j];
if(t[j+1]==s[i])
++j;
f[i]=j;
if(f[i]==m)
printf("%d\n",i-m+1);
}
for(int i=1;i<=m;++i)
printf("%d ",nxt[i]);
return 0;
}
【KMP】【字符串】KMP字符串匹配算法 学习笔记的更多相关文章
- No1_5.字符串的基本操作_Java学习笔记
import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Locale; import java. ...
- No1_6.字符串的基本操作2_Java学习笔记
import java.util.Scanner; import java.util.regex.Pattern; public class HelloString2 { public static ...
- BZOJ 3555: [Ctsc2014]企鹅QQ [字符串哈希]【学习笔记】
3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 2046 Solved: 749[Submit][Statu ...
- Linxu内核版本号后面多出字符串或者+号【学习笔记】
作者:庄泽彬 之前一直没有留意到但是最近在编译内核的时候版本号竟然多出了个加号+号或字符串, 后面终于找到原因了,原来config如果设置了CONFIG_LOCALVERSION_AUTO=y,内核的 ...
- 字符串Hash/树Hash学习笔记
哈希 Tags:字符串 作业部落 评论地址 一.概述 百度百科: 散列表(Hash table/哈希表),是根据关键码值(Key value)而直接进行访问的数据结构. 哈希表常用于比较两个字符串是否 ...
- javascript学习笔记(四) Number 数字类型
数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数 toExponential() 方法 用科学 ...
- BM和KMP字符串匹配算法学习
BM和KMP字符串匹配算法学习 分类: 研究与学习 字符串匹配BM(Boyer-Moore)算法学习心得 http://www.cnblogs.com/a180285/archive/2011/12/ ...
- 「学习笔记」字符串基础:Hash,KMP与Trie
「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...
- 串的应用与kmp算法讲解--学习笔记
串的应用与kmp算法讲解 1. 写作目的 平时学习总结的学习笔记,方便自己理解加深印象.同时希望可以帮到正在学习这方面知识的同学,可以相互学习.新手上路请多关照,如果问题还请不吝赐教. 2. 串的逻辑 ...
随机推荐
- SpringMVC Controller 的简单应用
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- opennebula 对接创建模板参数
{ "id": 8, "name": "c5d1390c-1930-45a5-a686-5cef38b319d7", "displ ...
- 30-懒省事的小明(priority_queue)
http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=55 懒省事的小明 时间限制:3000 ms | 内存限制:65535 KB 难度:3 ...
- 面试题:Java开发中的23种设计模式详解(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- c语言交换两个变量的值
有两个变量a 和b,想要交换它们的值 int a,b; 能不能这样操作呢? b=a; a=b; 不能啊,这样操作的意思是把a的值放到b中,然后b中的值已经被覆盖掉了,已经不是b原来的那个值了,所以是没 ...
- 1.ef 映射关系
1.edmx <?xml version="1.0" encoding="utf-8"?><edmx:Edmx Version="3 ...
- 设计模式07: Bridge 桥接模式(结构型模式)
Bridge 桥接模式(结构型模式) 抽象与实现 抽象不应该依赖于实现细节,实现细节应该依赖于抽象. 抽象B稳定,实现细节b变化 问题在于如果抽象B由于固有的原因,本身并不稳定,也有可能变化,怎么办? ...
- HTML5移动Web开发实战 PDF扫描版
<HTML5移动Web开发实战>提供了应对这一挑战的解决方案.通过阅读本书,你将了解如何有效地利用最新的HTML5的那些针对移动网站的功能,横跨多个移动平台.全书共分10章,从移动Web. ...
- Sobel算法
最近看了一些Sobel算法,并试了一下,源码如下: private void Sobel(Bitmap img) { int width = img.Width; int height = img.H ...
- docker run hello-world失败
提示镜像拉取失败,解决方案 到 https://cr.console.aliyun.com/ 注册一个账户 列表中就有 加速器 启动 Docker 端 右键 选择配置 在Docker Dae ...