讲KM♂P算法之前,我们先讲一个故♂事

有一天,sgg给了老obo一封信和一个单词,并给他一个任务:找出这封信出现了多少个单词,然后在规定时间内告诉他。

碰到这个问题,老obo会怎么做呢?

首先最直观的想法是什么?

就是先一维循环枚举信字符串的开头,再一维循环枚举单词的长度,一个一个判断是不是相同。这样的时间复杂度是O(n*m)的,n是信的长度,m是单词的长度。

当n*m小的时候,可以在规定时间内出解,然而,要是n*m很大呢?

我们想想有没有能优化以上算法的方法

我们假设一个next数组,next[i]代表1~i部分的字符串,最长的前缀等于后缀是多长,注意,1~i字符串的长度不能作为next[i]存储的答案。

这样有什么用呢?考虑这样:

我们考虑对单词做出这个数组:next={0,0,0,1,0,0,1,2,0}(从0位置开始)

来模拟一下我们一开始匹配的过程

设定一个指针j,初始在0

我们令i在信中从1扫描到8

:1位置,a[i]==b[j+1],我们令j++

2位置,a[i]==b[j+1],j++

3位置,a[i]==b[j+1],j++

4位置,a[i]==b[j+1],j++

5位置,a[i]==b[j+1],j++

6位置,a[i]==b[j+1],j++

7位置,a[i]==b[j+1],j++

8位置,a[i]!=b[j+1],那怎么办呢,如果让j直接等于0就相当于功亏一篑,于是我们让j=next[j],这样发现,之前匹配的s没有浪费掉,而且节约了时间。然后j=2,我们验证一下,在b中12位置的"sb"正好等于a中67位置的"sb"!

9位置,a[i]==b[j+1],j++

.........

直到11位置,j==m (m为单词长度),这表明了匹配成功!

那么我们怎么求这个next数组呢?

先给出模板

 void kmp(){
next[]=;int j=;
for (int i=;i<=m;i++){
while (j>&&b[j+]!=b[i]) j=next[j];
if (b[j+]==b[i]) j++;
next[i]=j;
}
}

就是这么简♂短,首先,next[1]=0,毋庸置疑,我们之前有声明过,next[i]不能等于1~i的长度。

然后对于后面的i,我们已知了next[i-1]的值,我们先让j=next[i-1],

如果b[j+1]=b[i],说明加上这个字符b[i],就等同于在原来相同的前缀后缀都增加了b[i]这个字符。

如果不相同,那就让j=next[j],这个部分比较难理解,我们画张♂图

假设这个字符串是单词,此时我的i已经到了9,j此时是4,当第10个字符出现的时候,如果它"失配"了,那么j=next[j],

其中我们知道,next[4]=2,我们看一下,长度为2的"sx"也正好是这个字符串的前缀和后缀,这是因为,如果我当前的next值为4,那么说明我前缀后缀都包含了"sxsx"这个字符串,当我再度让j=next[j],也就是j从4变成2的时候,"sx"也刚好是他们的前缀后缀了!

这样,O(m)计算next数组的方法就出来了。

obo:那怎么和信匹配呢?

给个模板:

 void match(){
int j=;
for (int i=;i<=n;i++){
while (j>&&b[j+]!=a[i]) j=next[j];
if (b[j+]==a[i]) j++;
if (j==m){
printf("Yes!");
return;
}
}
}

是不是很眼熟?没错,和处理next的程序很像,这是因为,kmp中处理next的过程正是"自我匹配"的过程,因为如果a能和b匹配,那a中也包含了b,所以匹配的过程本质是一样的。

KMP算法总♂结的更多相关文章

  1. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  2. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  3. KMP算法解析(转自图灵社区)

    KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...

  4. (原创)详解KMP算法

    KMP算法应该是每一本<数据结构>书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的文章,看久了好像也知道是怎么 ...

  5. KMP算法 - 求最小覆盖子串

    KMP与最小覆盖子串 最小覆盖子串:对于某个字符串s,它的最小覆盖子串指的是长度最小的子串p,p满足通过自身的多次连接得到q,最后能够使s成为q的子串. 比如: 对于s="abcab&quo ...

  6. KMP算法详解 --- 彻头彻尾理解KMP算法

    前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k. 但是问题在于如何求出这个最大前后缀长度呢? 我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破, 后来翻看 ...

  7. 字符串匹配(KMP算法)

    KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法. 举个例子来说,如果 ...

  8. KMP算法与一个经典概率问题

    考虑一个事件,它有两种概率均等的结果.比如掷硬币,出现正面和反面的机会是相等的.现在我们希望知道,如果我不断抛掷硬币,需要多长时间才能得到一个特定的序列. 序列一:反面.正面.反面序列二:反面.正面. ...

  9. Hihocode 1015 KMP算法

    时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互相帮助,在编程的学习道路上一同前进. ...

随机推荐

  1. Windows7下移植Qt4.8.4项目到QT5.2上时遇到的一些问题(包括三篇参考文章)

    文章来源:http://blog.csdn.net/ccf19881030/article/details/18220447 问题一:错误:C1083: 无法打开包括文件:“QApplication” ...

  2. redis maxmemory设置

    关于maxmemory的设置,如果redis的应用场景是作为db使用,那不要设置这个选项,因为db是不能容忍丢失数据的. 如果作为cache使用,则可以启用这个选项(其实既然有淘汰策略,那就是cach ...

  3. [VBA] excel获取单元格的超链接地址函数

    Function geturl(c As Range) As String geturl = c.Hyperlinks().Address End Function 设置超链接的函数是HYPERLIN ...

  4. Web开发之RSET API

    REST介绍 如果要说什么是REST的话,那最好先从Web(万维网)说起. 什么是Web呢?读者可以查看维基百科的词条(http://zh.wikipedia.org/zh-cn/Web),具体的我就 ...

  5. 在sae配置django项目

    1:使用sae开发必须有sae帐号,自己注册吧: 2:在sae上新建立一个python项目: 3:建立完成之后新建一个版本,即版本1: 4:获取svn的地址在eclipse中check下来: 5:注意 ...

  6. AAM(Active Appearance Model)算法介绍

    前面介绍ASM算法(http://blog.csdn.net/carson2005/article/details/8194317)的时候,笔者提到,ASM是基于统计形状模型的基础上进行的,而AAM则 ...

  7. Fragment 点击事件的穿透和重叠bug

    从A fragment跳转到B fragment ,为了返回时不从新加载A fragment内容,通常使用add方法来将a添加到后退栈. 在B Fragment 中点击一个空白区域,如果A Fragm ...

  8. let关键字

    作用: 与var类似, 用于声明一个变量特点: 只在块作用域内有效 不能重复声明 不会预处理, 不存在提升应用: 循环遍历加监听 //应用实例 <body> <button>测 ...

  9. C#语法糖: 扩展方法(常用)

    今天继续分享C#4.0语法糖的扩展方法,这个方法也是我本人比较喜欢的方法.大家先想想比如我们以前写的原始类型不能满足现在的需求,而需要在该类型中添加新的方法来实现时大家会怎么做.我先说一下我没有学习到 ...

  10. SDK文件夹下内容介绍

    Platform-Tools: 这是 adb, fastboot 等工具包.把解压出来的 platform-tools 文件夹放在 android sdk 根目录下,并把 adb所在的目录添加到系统 ...