大佬博客:https://blog.csdn.net/lee18254290736/article/details/77278769

对于正常的字符串模式匹配,主串长度为m,子串为n,时间复杂度会到达O(m*n),而如果用KMP算法,复杂度将会减少线型时间O(m+n)。

设主串为ptr="ababaaababaa";,要比较的子串为a=“aab”;

KMP算法用到了next数组,然后利用next数组的值来提高匹配速度,我首先讲一下next数组怎么求,之后再讲匹配方式。

next数组详解

首先是理解KMP算法的第一个难关是next数组每个值的确定,这个问题困恼我很长时间,尤其是对照着代码一行一行分析,很容易把自己绕进去。

定义一串字符串

ptr = "ababaaababaa";

next[i](i从1开始算)代表着,除去第i个数,在一个字符串里面从第一个数到第(i-1)字符串前缀与后缀最长重复的个数。

什么是前缀?

在“aba”中,前缀就是“ab”,除去最后一个字符的剩余字符串。

同理可以理解后缀。除去第一个字符的后面全部的字符串。

在“aba”中,前缀是“ab”,后缀是“ba”,那么两者最长的子串就是“a”;

在“ababa”中,前缀是“abab”,后缀是“baba”,二者最长重复子串是“aba”;

在“abcabcdabc”中,前缀是“abcabcdab”,后缀是“bcabcdabc”,二者最长重复的子串是“abc”;

这里有一点要注意,前缀必须要从头开始算,后缀要从最后一个数开始算,中间截一段相同字符串是不行的。

再回到next[i]的定义,对于字符串ptr = "ababaaababaa";

next[1] = -1,代表着除了第一个元素,之前前缀后缀最长的重复子串,这里是空 ,即"",没有,我们记为-1,代表空。(0代表1位相同,1代表两位相同,依次累加)。

next[2] = -1,即“a”,没有前缀与后缀,故最长重复的子串是空,值为-1;

next[3] = -1,即“ab”,前缀是“a”,后缀是“b”,最长重复的子串“”;

next[4] = 1,即"aba",前缀是“ab”,后缀是“ba”,最长重复的子串“a”;next数组里面就是最长重复子串字符串的个数

next[5] = 2,即"abab",前缀是“aba”,后缀是“bab”,最长重复的子串“ab”;

next[6] = 3,即"ababa",前缀是“abab”,后缀是“baba”,最长重复的子串“aba”;

next[7] = 1,即"ababaa",前缀是“ababa”,后缀是“babaa”,最长重复的子串“a”;

next[8] = 1,即"ababaaa",前缀是“ababaa”,后缀是“babaaa”,最长重复的子串“a”;

next[9] = 2,即"ababaaab",前缀是“ababaaa”,后缀是“babaaab”,最长重复的子串“ab”;

next[10] = 3,即"ababaaaba",前缀是“ababaaab”,后缀是“babaaaba”,最长重复的子串“aba”;

next[11] = 4,即"ababaaabab",前缀是“ababaaaba”,后缀是“babaaabab”,最长重复的子串“abab”;

next[12] = 5,即"ababaaababa",前缀是“ababaaabab”,后缀是“babaaaababa”,最长重复的子串“ababa”;

还有另外一种方法,我看的有的书上写着:

这里我们定义next[1] = 0 , next[1] = 1;

再分析ptr字符串,ptr = "ababaaababaa";

跟上一个的情况类似,

next[1] = 0 ,事先定义好的

next[2] = 1 ,事先定义好的

next[3] = 1 ,最长重复的子串“”;1代表没有重复,2代表有一个字符重复。

next[4] = 2 ,最长重复的子串“a”;追偿的长度加1,即为2.

next[5] = 3 ,以下都跟之前的一样,这种方法是最长的长度再加上一就可以了。

next[6] = 4

next[7] = 2

next[8] = 2

next[9] = 3

next[10] = 4

next[11] = 5

next[12] = 6

以上是next数组的详细解释。next数组求值 是比较麻烦的,剩下的匹配方式就很简单了。

next数组用于子串身上,根据上面的原理,我们能够推出子串a=“aab”的next数组的值分别为0,1,2.(按照我说的第二种方式算的)。

首先开始计算主串与子串的字符,设置主串用i来表示,子串用j来表示,如果ptr[i]与a[i]相等,那么i与j就都加1:

prt[1]与a[1]相等,i++,j++:

用代码实现就是

 if( j== ||  ptr[i]==a[j])
{
++i;
++j;
}

ptr[2]与a[2]不相等

此时ptr[2]!=a[2],那么令j = next[j],此时j=2,那么next[j] = next[2] = 1.那么此时j就等于1.这一段判断用代码解释的话就是:

if( ptr[i]!=a[j])
{
      j = next[j];
}

加上上面的代码进行组合:

在对两个数组进行比对时,各自的i,j取值代码:

 while( i<ptr.length && j< a.length)
{
if( j== || ptr[i]==a[i] )
{
++i;
++j; next[i] = j;
}
else
{
j = next[j];
}
}

此时将a[j]置于j此时所处的位置,即a[1]放到j=2处,因为在j=2时出现不匹配的情况。

此时再次计算是否匹配,可以看出来a[1]!=ptr[2],那么j = next[j],即此时j = next[1] = 0;

根据上面的代码,当j=0时,执行++i;++j;

此时就变为:

此时ptr[3] = a[1],继续向下走,下一个又不相等了,然后“aab”向后挪一位,这里不再赘述了,主要的思想已经讲明白了。到最后一直到i = 8,j=3时匹配成功,KMP算法结束。整个过程就结束了。

talk is cheap,show me the code.

 #include<stdio.h>
#include<string.h>
#define N 1000005
char s[N];
char p[N];
int next[N];
int m,n;
void getnext()
{
int j=,k=-;
next[]=-;
while(j<m)
{
if(k==-||p[j]==p[k])
{
j++;
k++;
next[j]=k;
}
else
k=next[k];
}
}
int kmp()
{
int i=,j=,ans=;
getnext();
while(i<n)
{
if(j==-||s[i]==p[j])
{
i++;
j++;
}
else
j=next[j];
if(j==m)
ans++;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf(" %s %s",&p,&s);
m=strlen(p);
n=strlen(s);
printf("%d\n",kmp());
}
return ;
}

kmp(详解)的更多相关文章

  1. KMP详解之二

    KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...

  2. 字符串模式匹配算法--BF和KMP详解

    1,问题描述 字符串模式匹配:串的模式匹配 ,是求第一个字符串(模式串:str2)在第二个字符串(主串:str1)中的起始位置. 注意区分: 子串:要求连续   (如:abc 是abcdef的子串) ...

  3. KMP详解

    原文: http://blog.csdn.net/v_july_v/article/details/7041827 从头到尾彻底理解KMP 1. 引言 本KMP原文最初写于2年多前的2011年12月, ...

  4. 模式串匹配KMP详解

    关于KMP模式串匹配网上蛮多的. 对于KMP有自己理解所以写下来希望能够对你们的学习有帮助. 之前暑假的时候学过,然后好长时间没用发现又忘了,现在再看看发现有了新的理解. ============== ...

  5. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  6. [转] KMP算法详解

    转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段.    我们这里说的K ...

  7. KMP算法详解(转自中学生OI写的。。ORZ!)

    KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...

  8. KMP算法学习(详解)

    kmp算法又称“看毛片”算法,是一个效率非常高的字符串匹配算法.不过由于其难以理解,所以在很长的一段时间内一直没有搞懂.虽然网上有很多资料,但是鲜见好的博客能简单明了地将其讲清楚.在此,综合网上比较好 ...

  9. 字符串匹配KMP算法详解

    1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有比较详细的通俗易懂的讲解,另一方面也怪自己没有沉下心来研究.最近在leetcode上又遇见字符串匹配的题目,以此 ...

随机推荐

  1. BZOJ3894:文理分科(最大流)(同BZoj3438)

    文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠 结过) 小P所在的班级要进行文理分科.他的班级可以用一个n*m的矩阵进行 描述,每个格子代表一个同学的座位.每位同学必须从文科和理科中选 ...

  2. Sublime Text 3常用插件安装

    Sublime Text 3常用插件安装 PS:sublime是笔者用过的最好用的编辑器,也是最轻量级,功能最强大的编辑器.好东西应该被分享! 1.直接安装 --下载安装包解压缩到Packages目录 ...

  3. elixir 集成ejabberd

    备注: 我开发测试的环境时centos 1. 预备环境 1. openssl yum install -y  openssl-devel 2. xml yum install -y expat-dev ...

  4. 嵌入式无法使用QAudioDeviceInfo类

    修改: 1.修改pro文件 增加    QT += multimedia 2.修改Makefile文件,LIBS = $(SUBLIBS)  -L/opt/qt-4.8.5/lib -lQtMulti ...

  5. Java通过aws java sdk在AWS S3上进行操作客户端

    有两种方式可以安装aws java sdk:方式一:可以在这个网站上下载适用于 Java 的 AWS 开发工具包https://aws.amazon.com/cn/sdk-for-java/点击网页右 ...

  6. 移动端固定头部和固定左边第一列的实现方案(Vue中实现demo)

    最近移动端做一份报表,需要左右滚动时,固定左边部分:上下滚动时,固定头部部分. 代码在Vue中简单实现 主要思路是: a.左边部分滚动,实时修改右边部分的滚动条高度 b.头部和内容部分都设置固定高度, ...

  7. opencv读取中文路径报错的问题

    ) ## 经验证,不需要再转bgr,myImread的读图结果已经是和imread一样的 return img

  8. CXF+Spring搭建webservice服务

    Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS .这些 Services 可以支持多 ...

  9. Django 组件-中间件

    中间件 中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好 ...

  10. Java中的自动类型转换/隐式类型转换

    整型.实型(常量).字符型数据可以混合运算.运算中,不同类型的数据先转化为同一类型,然后进行运算. 转换从低级到高级. 自动类型转换必须满足转换前的数据类型的位数要低于转换后的数据类型,例如: sho ...