<转>KMP算法详解
看了好久的KMP算法,都一直没有看明白,直到看到了这篇博客http://www.tuicool.com/articles/e2Qbyyf让我瞬间顿悟。
如果你看不懂 KMP 算法,那就看一看这篇文章 ( 绝对原创,绝对通俗易懂 )
KMP 算法,俗称“看毛片”算法,是字符串匹配中的很强大的一个算法,不过,对于初学者来说,要弄懂它确实不易。整个寒假,因为家里没有网,为了理解这个算法,那可是花了九牛二虎之力!不过,现在我基本上对这个算法理解算是比较透彻了!特写此文与大家分享分享!
我个人总结了, KMP 算法之所以难懂,很大一部分原因是很多实现的方法在一些细节的差异。怎么说呢,举我寒假学习的例子吧,我是看了一种方法后,似懂非懂,然后去看另外的方法,就全都乱了!体现在几个方面: next 数组,有的叫做“失配函数”,其实是一个东西; next 数组中,有的是以下标为 0 开始的,有的是以 1 开始的; KMP 主算法中,当发生失配时,取的 next 数组的值也不一样!就这样,各说各的,乱的很!
所以,在阐述我的理解之前,我有必要说明一下,我是用 next 数组的, next 数组是以下标 0 开始的!还有,我不会在一些基础的概念上浪费太多,所以你在看这篇文章时必须要懂得一些基本的概念,例如 “ 朴素字符串匹配 ”“ 前缀 ” , “ 后缀 ” 等!还有就是,这篇文章的每一个字都是我辛辛苦苦码出来的,图也是我自己画的!如果要转载,请注明出处!好了,开始吧!
假设在我们的匹配过程中出现了这一种情况:
根据 KMP 算法,在该失配位会调用该位的 next 数组的值!在这里有必要来说一下 next 数组的作用!说的太繁琐怕你听不懂,让我用一句话来说明:
返回失配位之前的最长公共前后缀!
好,不管你懂不懂这句话,我下面的文字和图应该会让你懂这句话的意思以及作用的!
首先,我们取之前已经匹配的部分(即蓝色的那部分!)
我们在上面说到 next 数组的作用时,说到 “ 最长公共前后缀 ” ,体现到图中就是这个样子!
接下来,就是最重要的了!
没错,这个就是 next 数组的作用了 :
返回当前的最长公共前后缀长度,假设为 len 。因为数组是由 0 开始的,所以 next 数组让第 len 位与主串匹配就是拿最长前缀之后的第 1 位与失配位重新匹配,避免匹配串从头开始!如下图所示!
(重新匹配刚才的失配位!)
如果都说成这样你都不明白,那么你真的得重新理解什么是 KMP 算法了!
接下来最重要的,也是 KMP 算法的核心所在,就是 next 数组的求解!不过,在这里我找到了一个全新的理解方法!如果你懂的上面我写的的,那么下面的内容你只需稍微思考一下就行了!
跟刚才一样,我用一句话来阐述一下 next 数组的求解方法,其实也就是两个字:
继承
a 、当前面字符的前一个字符的对称程度为 0 的时候,只要将当前字符与子串第一个字符进行比较。这个很好理解啊,前面都是 0 ,说明都不对称了,如果多加了一个字符,要对称的话最多是当前的和第一个对称。比如 agcta 这个里面 t 的是 0 ,那么后面的 a 的对称程度只需要看它是不是等于第一个字符 a 了。
b 、按照这个推理,我们就可以总结一个规律,不仅前面是 0 呀,如果前面一个字符的 next 值是 1 ,那么我们就把当前字符与子串第二个字符进行比较,因为前面的是 1 ,说明前面的字符已经和第一个相等了,如果这个又与第二个相等了,说明对称程度就是 2 了。有两个字符对称了。比如上面 agctag ,倒数第二个 a 的 next 是 1 ,说明它和第一个 a 对称了,接着我们就把最后一个 g 与第二个 g 比较,又相等,自然对称成都就累加了,就是 2 了。
c 、按照上面的推理,如果一直相等,就一直累加,可以一直推啊,推到这里应该一点难度都没有吧,如果你觉得有难度说明我写的太失败了。
当然不可能会那么顺利让我们一直对称下去,如果遇到下一个不相等了,那么说明不能继承前面的对称性了,这种情况只能说明没有那么多对称了,但是不能说明一点对称性都没有,所以遇到这种情况就要重新来考虑,这个也是难点所在。
如果蓝色的部分相同,则当前 next 数组的值为上一个 next 的值加一,如果不相同,就是我们下面要说的!
如果不相同,用一句话来说,就是:
从前面来找子前后缀
1 、如果要存在对称性,那么对称程度肯定比前面这个的对称程度小,所以要找个更小的对称,这个不用解释了吧,如果大那么就继承前面的对称性了。
2 、要找更小的对称,必然在对称内部还存在子对称,而且这个必须紧接着在子对称之后。
如果看不懂,那么看一下图吧!
好了,我已经把该说的尽可能以最浅显的话和最直接的图展示出来了,如果还是不懂,那我真的没有办法了!
说了这么多,下面是代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100 void cal_next( char * str, int * next, int len )
{
int i, j; next[] = -;
for( i = ; i < len; i++ )
{
j = next[ i - ];
while( str[ j + ] != str[ i ] && ( j >= ) )
{
j = next[ j ];
}
if( str[ i ] == str[ j + ] )
{
next[ i ] = j + ;
}
else
{
next[ i ] = -;
}
}
} int KMP( char * str, int slen, char * ptr, int plen, int * next )
{
int s_i = , p_i = ; while( s_i < slen && p_i < plen )
{
if( str[ s_i ] == ptr[ p_i ] )
{
s_i++;
p_i++;
}
else
{
if( p_i == )
{
s_i++;
}
else
{
p_i = next[ p_i - ] + ;
}
}
}
return ( p_i == plen ) ? ( s_i - plen ) : -;
} int main()
{
char str[ N ] = {};
char ptr[ N ] = {};
int slen, plen;
int next[ N ]; while( scanf( "%s%s", str, ptr ) )
{
slen = strlen( str );
plen = strlen( ptr );
cal_next( ptr, next, plen );
printf( "%d\n", KMP( str, slen, ptr, plen, next ) );
}
return ;
}
<转>KMP算法详解的更多相关文章
- kmp算法详解
转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...
- [转] KMP算法详解
转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的K ...
- KMP算法详解(转自中学生OI写的。。ORZ!)
KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...
- 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串
1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...
- 数据结构4.3_字符串模式匹配——KMP算法详解
next数组表示字符串前后缀匹配的最大长度.是KMP算法的精髓所在.可以起到决定模式字符串右移多少长度以达到跳跃式匹配的高效模式. 以下是对next数组的解释: 如何求next数组: 相关链接:按顺序 ...
- KMP算法详解&&P3375 【模板】KMP字符串匹配题解
KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...
- 字符串匹配KMP算法详解
1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...
- KMP算法详解-彻底清楚了(转载+部分原创)
引言 KMP算法指的是字符串模式匹配算法,问题是:在主串T中找到第一次出现完整子串P时的起始位置.该算法是三位大牛:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,以其名字首字 ...
- KMP算法详解 --- 彻头彻尾理解KMP算法
前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k. 但是问题在于如何求出这个最大前后缀长度呢? 我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破, 后来翻看 ...
- 字符串匹配的KMP算法详解及C#实现
字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...
随机推荐
- window 服务(一)
windows服务应用程序是一种长期运行在操作系统后台的程序,它对于服务器环境特别适合,它没有用户界面,不会产生任何可视输出,任何用户输出都回被写进windows事件日志.计算机启动时,服务会自动开始 ...
- hive 进阶笔记
-- mysql方式 create table account_channel(account_ String,channel_ String) as select a.account,b.chann ...
- Hadoop的体系结构之MapReduce的体系结构
MapReduce的体系结构 Hadoop MapReduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在上千个商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上TB的数据集. ...
- ContikiMAC RDC协议
http://www.mamicode.com/info-detail-1348767.html
- JDBC 查询的三大参数 setFetchSize prepareStatement(String sql, int resultSetType, int resultSetConcur)
JDBC 查询的三大参数 本文转载至 http://blog.csdn.net/turkeyzhou/article/details/5115228 DBC1.0 .JDBC2.0 .JDBC3.0 ...
- Arrays.sort和Collections.sort实现原理解析
Arrays.sort和Collections.sort实现原理解析 1.使用 排序 2.原理 事实上Collections.sort方法底层就是调用的array.sort方法,而且不论是Collec ...
- ARDUINO PWM
转至:http://www.sl088.com/voyage/2012/10/11506.slboat#.E5.8F.91.E7.8E.B0 http://www.engblaze.com/micro ...
- Intellij Idea14 jstl标签的引入
习惯了eclipse和myeclipse开发的我们总是依赖于系统的插件,而当我想当然的以为IntelliJ IDEA 的jstl 的使用应该和myeclispe一样,当时使用起来却到处碰壁,完全找不到 ...
- mysql没有my.ini文件
解决方法: 上面的任意一个文件拷贝一份,重命名my.ini.
- 做asp.net的在别人眼中都是渣渣吗?
做asp.net的在别人眼中都是渣渣吗?