一、简介

    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. Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制

    1 Stream Stream 是 Java 8 提供的一系列对可迭代元素处理的优化方案,使用 Stream 可以大大减少代码量,提高代码的可读性并且使代码更易并行. 2 迭代 2.1 需求 随机创建 ...

  2. Win10 linux子系统Ubuntu下显示图形界面

    转载 https://jingyan.baidu.com/article/ed2a5d1f98577809f6be17a3.html 打开终端界面,在这个窗口测试一下ls命令,无误. # 更新 sud ...

  3. 用Linq取两个数组的差集

    两个数组,取其差集,用Linq做比较方便,效率也比较高,具体如下示例 有两个数组list1 和list2 ,如下 List<int> list1 = new List<int> ...

  4. C# 将一个DataTable的结构直接复制到另一个DataTable

    DataTable.Clone();//仅复制表结构DataTable.Copy();//复制表结构及数据 DataTable.ImportRow(DataRow);//复制行数据到新表 DataRo ...

  5. New for ASP.NET Web Pages: Conditional attributes

    from:http://www.mikepope.com/blog/AddComment.aspx?blogid=2353 March 01, 2012 The beta release of ASP ...

  6. 【Head First Java 读书笔记】(一)基本概念

    Java的工作方式 你要做的事情就是会编写源代码 Java的程序结构 类存于源文件里面 方法存在类中 语句存于方法中 剖析类 当Java虚拟机启动执行时,它会寻找你在命令列中所指定的类,然后它会锁定像 ...

  7. MongoDB整理笔记のGridFS

    GridFS 是一种将大型文件存储在MongoDB 数据库中的文件规范.所有官方支持的驱动均实现了GridFS 规范. GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件. 官网学习 ...

  8. 搭建自己的git服务器--gogs

    //@desn:搭建自己的git服务器--gogs //@desn:码字不宜,转载请注明出处 //@author:张慧源  <turing_zhy@163.com> //@date:201 ...

  9. Arduino I2C + 数字式环境光传感器BH1750FVI

    BH1750FVI是日本罗姆(ROHM)半导体生产的数字式环境光传感IC.其主要特性有: I2C数字接口,支持速率最大400Kbps 输出量为光照度(Illuminance) 测量范围1~65535 ...

  10. Android ViewPager + Fragment的布局

    ViewPager And Fragment 1.之前有篇博客是讲ViewPager的用法的:http://www.cnblogs.com/liangstudyhome/p/3773156.html ...