KMP算法是BF算法的改进,主要是消除了主串指针的回溯,提高算法效率。

先简单介绍一下BF算法:

基本思路:

从目标串s的第一个字符开始和模式串的第一个字符比较,相等逐个比较后续字符,否则从目标串的第二个字符开始从新与模式串的第一个字符进行比较。以此类推。。

其时间复杂度为O(m*n)

BF-CODE:

 int BF(char s[],char t[])
{
int i=,j=;
int lens=strlen(s);
int lent=strlen(t);
while(i<lens&&j<lent)
{
if(s[i]==t[j])//继续匹配下一个字符
{
i++;
j++;
}//主串和子串依次匹配下一个字符
else
{
i=i-j+;//主串从下一个位置开始匹配
j=;//子串从头开始匹配
}
}
if(j>=lent)
return (i-lent);
else
return -;
}

KMP算法:

如何消除主串指针的回溯呢?需要分析模式串t,对于t的每个字符t[j],若存在一个整数K,使得模式t中k所指字符之前的k个字符依次与tj的前面k个字符相同,并与主串s中i所指的字符之前的k个字符相等。那么就可以利用这种信息避免不必要的回溯了。这种信息我们把它记录在模式串的next数组中,那么如何来求next数组呢?

怎么求串的模式值next[n]

      定义
             (1)next[0]= -1 意义:任何串的第一个字符的模式值规定为-1。
      (2)next[j]=k    意义:模式串T中下标为j的字符,如果j的前面最多有k个字符与开头的k个字符相等,且T[j] != T[k] (1≤k<j)。即T[0]T[1]T[2]。。。T[k-               1]==T[j-k]T[j-k+1]T[j-k+2]…T[j-1]且T[j] != T[k].(1≤k<j);
       (3) next[j]=0   意义:除(1)(2)(3)的其他情况。

GET-NEXT CODE:

 void get-next(char s[],char t[])
{
int j,k;
j=;
k=-;
next[]=-;
int lent=strlen(t);
int lens=strlen(s);
while(j<lent-)
{
if(k==-||t[j]==t[k])
{
j++;
k++;
next[j]=k;
}
else
k=next[k];
}
}

kmp算法的思想是:设s为目标穿,t为模式串,并设i,j指针分别指示目标串和模式串中正待比较的字符,令i,j的初始值均为0 ,若有s[i]=t[j],则i,j分别增加1,否则,j再退回到j=next[j]的位置,继续比较。直到出现下面两种情况:1.j退回到某个j=next[j]的位置时有s[i]=t[j],则指针各增加一后继续匹配,2.j退回到j=-1,令指针各增加1,下一次比较s[i+1]和t[0].时间复杂度是O(N+M).

KMP-CODE:

 int kmp(char s[],char t[])
{
int lent=strlen(t);
int lens=strlen(s);
int i=,j=;
while(i<lens&&j<lent)
{
if(j==-||s[i]==t[j])
{
i++;
j++;
}
else
j=next[j];//i不变j退后
}
if(j>=lent)
return (i-lent);//返回匹配模式串的首字符下标
else
return -;
}

kmp算法基本讲完了,下面来说说Kmp的几个应用:

1.求最小循环节和最大重复次数(此段非原创,摘自http://www.cnblogs.com/jackge/archive/2013/01/05/2846006.html)

  在KMP算法的使用中,首要任务就是获取一个字符串的next数组,所以我们得明白next数组的含义(最好的方法是自己弄个例子,在草稿纸上模拟一下),在这里,通俗一点  讲,next[k] 表示,在模式串的 k 个字符失配了,然后下一次匹配从 next[k] 开始(next[k] 中保存的是该失配字符的前一个字符在前面出现过的最近一次失配的字符后面的  一个字符的位置,有点绕口,自己写个例子看看就明白了,也可以继续往下看,有介绍,然后再自己尝试写写 )。

  至于next数组为什么可以用来求重复前缀呢,而且求出来的重复前缀是最小的呢?

我们来看一下求next数组的代码:

void getnext(int len){
int i=,j=-;
next[]=-;
while(i<len){
if(j==- || str[i]==str[j]){
i++;j++;
next[i]=j;
}else
j=next[j];
}
}

    个人认为,next数组在求解的过程中,用到了KMP的思想,当前失配了,就回溯到上一个next,请见 j=next[j] ,先说个结论,如果到位置 i ,如果有 i%(i-  next(i))==0 , 那说明字符串开始循环了,并且循环到 i-1 结束,为什么这样呢?

  我们先假设到达位置 i-1 的时候,字符串循环了(到i-1完毕),那么如果到第i个字符的时候,失配了,根据next数组的求法,我们是不是得回溯?

  然而回溯的话,由于字符串是循环的了(这个是假定的),next[i] 是不是指向上一个循环节的后面一个字符呢??

  是的,上一个循环节的末尾是 next[i]-1 ,然后现在循环节的末尾是 i-1 ,然么循环节的长度是多少呢?

  所以,我们有 (i - 1) - ( next[i] - 1 ) = i - next[i]  就是循环节的长度(假设循环成立的条件下),但是我们怎么知道这个循环到底成立吗?

  现在我们已经假设了 0————i-1 循环了,那么我们就一共有i 个字符了,如果有 i % ( i - next[i] ) == 0,总的字符数刚好是循环节的倍数,那么说明这个循环是成立的。

  注意还有一点,如果 next[i] == 0,即使符合上述等式,这也不是循环的,举个反例

  0   1    2   3   4   5

  a    b   c   a   b   d

  -1   0   0   0   1   2

  下标为1,2,3的next值均为0,那么 i%(i-next【i】)=i%i==0,但是这个并不是循环。

  解释完毕,然后再来看下,为什么求出来的循环节长度是最小的呢?

  因为next数组失配的时候,总是回溯到最近的循环节,所以i-next【i】就是最小的循环节长度

    为什么求出来的循环次数是最多的呢?

    循环节长度是最小的了,那么循环次数肯定是最多的了。

  总结一下,如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 则说明字符串循环,而且

  循环节长度为:   i - next[i]

  循环次数为:       i / ( i - next[i] )

             There is a meaning for wings that cannot fly,it's a previous memory of when you once flew through the sky.这篇博文写得挺认真的,希望大家多多指点~噶呜~~

                                                                           

KMP 知识点总结的更多相关文章

  1. KMP 知识点整理

    1.扩展KMP 2.最大表示法 3.最小表示法 (扩展KMP) hdu2594  模板题 #include <iostream> #include <cstdio> #incl ...

  2. [知识点]KMP算法

    // 此博文为迁移而来,写于2015年5月24日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w1iw.html 1.前 ...

  3. 链表、栈、队列、KMP相关知识点

    链表.栈与队列.kmp; 数组模拟单链表: 用的最多的是邻接表--就是多个单链表: 作用:存储树与图 需要明确相关定义: 为什么需要使用数组模拟链表 比使用结构体 或者类来说 速度更快 代码简洁 算法 ...

  4. KMP算法简明扼要的理解

    KMP算法也算是相当经典,但是对于初学者来说确实有点绕,大学时候弄明白过后来几年不看又忘记了,然后再弄明白过了两年又忘记了,好在之前理解到了关键点,看了一遍马上又能理解上来.关于这个算法的详解网上文章 ...

  5. 4种字符串匹配算法:KMP(下)

    回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...

  6. 再谈KMP

    昨天讲解了字典树和AC自动机后感觉整个人都蒙掉了.还好就是自己今天在网上看见一篇对KMP讲解非常详细的帖子,果断收藏.(点击这里查看) 然后代码的实现也就简单分析一些了,具体的知识点大家直接自己链接过 ...

  7. 数据结构学习之字符串匹配算法(BF||KMP)

    数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 ​ 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 ​ 编写出BF暴力匹配.KM ...

  8. KMP模板实现

    看了出题知识点才发现自己连KMP都没有好好的理解,甚至一共就打过一次板子=-= 于是照着之前的课件学了一学...发现没怎么弄懂qwq 我太弱啦! 找了一篇自认为全网最好的介绍 觉得写得很棒 字符串匹配 ...

  9. JSOI2020备考知识点复习

    我太菜了qaq,我好爱咕咕咕啊 在NOIP2018爆炸后,我只能指望着在JSOI2019JSOI2020上咸鱼翻身(flag*1) 所以,我要开始复习学习(flag*2) 此博客文会不定时更新qaq( ...

随机推荐

  1. getElementById的缩略

    谁都知道document.getElementById这个方法写起来比较麻烦,所以有时候我们会使用jq或者自己写一个小函数去封装,但是我这次说的缩略不同于往常的函数封装 在以前,我做过很多这样的尝试, ...

  2. perl 面向对象 use base

    1.XXX.pm 文件里面的第一行要是:package XXX: 2.要有构造函数 sub new,实现如下: sub new { my $class = shift; # Get the reque ...

  3. 如何使用不同dll的相同namespace下的相同接口

    问题: 程序里加载了2个dll,这2个dll里都声明了同样的命名空间(这个不违法),然后在这个同样的命名空间下,他俩又定义了同名的interface. 然后我程序里直接using这个命名空间,使用这个 ...

  4. OPENSSL库的使用-DES篇

    一.单DES算法ECB模式加解密 1.使用函数DES_set_key_unchecked设置密钥 2.使用函数DES_ecb_encrypt来进行数据加解密 void DES_ecb_encrypt( ...

  5. hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流推断 )

    题意:有n个点和m条有向边构成的网络.每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏全部S到T的路径的费用和 > 毁坏全部T到 ...

  6. android 由于界面控件过多耗时处理办法

    在开发当中,有时候可能界面嵌套较多,那么导致控件实例化增多,有时候会大大影响界面加载的速度,特别在viewpage中的时候,要是第一页里面要inflate一个控件比较多的页面的时候,就会影响整个Act ...

  7. linux 解决Ubuntu编译内核uImage出现问题“mkimage” command not found - U-Boot images will not be built问题

    解决Ubuntu编译内核uImage出现问题“mkimage” command not found - U-Boot images will not be built问题 http://www.lin ...

  8. delphi高手突破之异常及错误处理

    什么是异常?为什么要用它? 所谓“异常”是指一个异常类的对象.Delphi的VCL中,所有异常类都派生于Exception类.该类声明了异常的一般行为.性质.最重要的是,它有一个Message属性可以 ...

  9. Web用户控件

    用户控件是个什么东西?自定义的反复重用的控件集合 注意:创建好用户控件后,必须添加到其他web页中才能显示出来,不能直接作为一个网页来显示,因此也就不能设置用户控件为“起始页”. 用户控件与ASP.N ...

  10. Axure快捷键大全 Axure RP Pro 6.5快捷键

    习惯用Axure快捷键会让你做原型的时候更得心应手.Axure中文网总结了常用的一些快捷键分享给大家 . Axure RP Pro 6.5快捷键大全,如有疏漏,欢迎补充. 基本快捷键:   打开:Ct ...