【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. 串的逻辑 ...
随机推荐
- linux安全关机脚本
linux安全关机脚本 在断电4分钟后判断关键 目的:在断电以后服务器连接UPS,UPS最多只能支持5分钟也会没电,所以在这里做个判断,如果断电4分钟后,市电还没来就关机. 以下两个设备为两个下路由器 ...
- c语言实践 打印字母三角形
效果如下: 我是怎么想的: 总共需要打印6行字母,那么就需要一个循环来控制打印第几行,大概代码如下: for(int i=0;i<6;i++) { } 每行都会打印字母,而且循环越往后,需要打印 ...
- 8.INSERT INTO 语句 UPDATE 语句
1. INSERT INTO 语句 INSERT INTO 语句用于向表格中插入新的行. 语法 INSERT INTO 表名称 VALUES (值1, 值2,....) INSERT INTO Per ...
- keys()
keys():返回一个数组,里面是符合匹配模式的键列表 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $pattern = ...
- Linux安装tomcat服务器
1.下载tomcat(区分windows和Linux,以tar.gz为后缀名的是Linux操作系统使用的). 官网下载地址:http://test.m.xiaoyuanhao.com/micro/ap ...
- Python基础入门-While循环
讲完了for循环我们继续来看第二个循环,那就是while循环,while循环和for循环虽然都是循环,但是有着本质的不同.我们先来看下她们之间的区别和联系: While循环和for循环区别: 1.fo ...
- 一些webGL地球的网址
测试浏览器的webgl支持情况:https://browserleaks.com/webgl 或者 https://github.com/AnalyticalGraphicsInc/webglrepo ...
- jqGrid查询案例(实用)
var ThisTime = getNowFormatDate(); //加载表格 function GetGrid() { var selectedRowIndex = 0; var $gridTa ...
- Java实现四则运算 谢雅淇 袁杏仪
GitHub链接:https://github.com/3216004716/four-operations.git 项目相关要求 使用 -n 参数控制生成题目的个数,例如 Myapp.exe -n ...
- 读写文本文件之StreamReader和StreamWriter
private string _filePath = @"1.txt"; //查询文件是否存在,如果不存在,则创建 if (!File.Exists(_filePath)) { u ...