一、简介

    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字符串匹配算法 学习笔记的更多相关文章

  1. No1_5.字符串的基本操作_Java学习笔记

    import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Locale; import java. ...

  2. No1_6.字符串的基本操作2_Java学习笔记

    import java.util.Scanner; import java.util.regex.Pattern; public class HelloString2 { public static ...

  3. BZOJ 3555: [Ctsc2014]企鹅QQ [字符串哈希]【学习笔记】

    3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 2046  Solved: 749[Submit][Statu ...

  4. Linxu内核版本号后面多出字符串或者+号【学习笔记】

    作者:庄泽彬 之前一直没有留意到但是最近在编译内核的时候版本号竟然多出了个加号+号或字符串, 后面终于找到原因了,原来config如果设置了CONFIG_LOCALVERSION_AUTO=y,内核的 ...

  5. 字符串Hash/树Hash学习笔记

    哈希 Tags:字符串 作业部落 评论地址 一.概述 百度百科: 散列表(Hash table/哈希表),是根据关键码值(Key value)而直接进行访问的数据结构. 哈希表常用于比较两个字符串是否 ...

  6. javascript学习笔记(四) Number 数字类型

    数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数  toExponential() 方法 用科学 ...

  7. BM和KMP字符串匹配算法学习

    BM和KMP字符串匹配算法学习 分类: 研究与学习 字符串匹配BM(Boyer-Moore)算法学习心得 http://www.cnblogs.com/a180285/archive/2011/12/ ...

  8. 「学习笔记」字符串基础:Hash,KMP与Trie

    「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...

  9. 串的应用与kmp算法讲解--学习笔记

    串的应用与kmp算法讲解 1. 写作目的 平时学习总结的学习笔记,方便自己理解加深印象.同时希望可以帮到正在学习这方面知识的同学,可以相互学习.新手上路请多关照,如果问题还请不吝赐教. 2. 串的逻辑 ...

随机推荐

  1. MyBatis—实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  2. Ubuntu无法安装rpm包,ubuntu RPM should not be used directly install RPM packages, use Alien instead!

    Ubuntu无法安装rpm包,ubuntu RPM should not be used directly install RPM packages, use Alien instead! 简单来说, ...

  3. Mock Server实践

    转载自 https://tech.meituan.com/mock-server-in-action.html 背景 在美团服务端测试中,被测服务通常依赖于一系列的外部模块,被测服务与外部模块间通过R ...

  4. 在Linux中监视IO性能

    dd命令 iostat命令 理解iostat的各项输出 iostat的应用实例 附:在Windows中监视IO性能 延伸阅读 dd命令 dd其实是工作于比较低层的一个数据拷贝和转换的*nix平台的工具 ...

  5. WIN XP蓝屏代码大全

    转自:廊坊师范学院信息技术提高班---韩正阳 http://blog.csdn.net/jiudihanbing WIN XP蓝屏代码大全WIN XP蓝屏代码大全一.蓝屏含义 1.故障检查信息 *** ...

  6. poj 1611 The Suspects(第一道并查集)

    题意: 有N个学生,编号为0-n-1,现在0号学生感染了非典,凡是和0在一个社团的人就会感染, 并且这些人如果还参加了别的社团,他所在的社团照样全部感染,社团个数为m,求感染的人数. 输入: n代表人 ...

  7. linux内存监控 free

    free 命令详解: 执行命令后总共四行. 第一行: 列头 第二行: total 内存总数: 32881776 used 已经使用的内存数: 8324796 free 空闲的内存数: 24556980 ...

  8. Git代码冲突常见解决方法

    在发布这个配置文件的时候,会发生代码冲突: error: Your local changes to the following files would be overwritten by merge ...

  9. C#ThreadPool学习

    一.简介 提供一个线程池,该线程池可用于执行任务.发送工作项.处理异步 I/O.代表其他线程等待以及处理计时器 注意:线程池中启动的线程都是后台线程 二.主要方法 GetAvailableThread ...

  10. 如何优雅地使用win10的Linux子系统

    转自: http://blog.csdn.net/u010053050/article/details/52388663 http://www.rehack.cn/techshare/devtools ...