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. Android 锁屏状态/锁屏密码等相关

    Android 锁屏状态/锁屏密码等相关 开始是在设备管理器方面找方法,但一直不行,可能在公司系统组同事的帮助下,知道KeyguardManager这个类 /** * 当前系统锁屏是否有密码 * @p ...

  2. 获取证书以用于 Windows Azure 网站 (WAWS)

    编辑人员注释:本文章由 Windows Azure 网站团队的项目经理 Erez Benari 撰写. 近年来,随着网络犯罪的上升,使用 SSL 保护网站逐渐成为一项备受追捧的功能,Windows A ...

  3. Android开发之SoundPool使用具体解释

    使用SoundPool播放音效 假设应用程序常常播放密集.急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了.由于MediaPlayer存在例如以下缺点: 1)      ...

  4. android 中webview调用js

    1.android中利用webview调用网页上的js代码. Android 中可以通过webview来实现和js的交互,在程序中调用js代码,只需要将webview控件的支持js的属性设置为true ...

  5. Java基础05 实施接口

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在封装与接口中,private关键字封装了对象的内部成员.经过封装,产品隐藏了内部 ...

  6. [置顶] c#验证码识别、图片二值化、分割、分类、识别

    c# 验证码的识别主要分为预处理.分割.识别三个步骤 首先我从网站上下载验证码 处理结果如下: 1.图片预处理,即二值化图片 *就是将图像上的像素点的灰度值设置为0或255. 原理如下: 代码如下: ...

  7. @produces在spring mvc中是什么意思

    @RequestMapping(value = "/produces", produces = "application/json"):表示将功能处理方法将生产 ...

  8. 6个最佳的开源Python应用服务器

    6个最佳的开源Python应用服务器 首先,你知道什么是应用服务器吗?应用服务器通常被描述为是存在于服务器中心架构中间层的一个软件框架. AD: 首先,你知道什么是应用服务器吗?应用服务器通常被描述为 ...

  9. C# c++ 传递函数指针

    C#和c++之间相互传递函数指针 在C++和C#之中都有很多callback method,可以相互调用吗,怎么传递,是我表弟的问题. 1.定义c++ dll ,导出方法 // sort.cpp : ...

  10. Swift - final关键字的介绍,以及使用场景

    final关键字在大多数的编程语言中都存在,表示不允许对其修饰的内容进行继承或者重新操作.Swift中,final关键字可以在class.func和var前修饰. 通常大家都认为使用final可以更好 ...