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. 四、Nginx负载均衡upstream

    user www; worker_processes ; error_log /usr/local/nginx/logs/error.log crit; pid /usr/local/nginx/lo ...

  2. linux下Python网络编程框架-Twisted安装

    Twisted是python下的用来进行网络服务和应用程序编程的框架,安装Twisted前需要系统预先安装有python. 一.安装Twisted http://twistedmatrix.com/R ...

  3. mysql basic operation,mysql总结

    mysql> select * from wifi_data where dev_id like "0023-AABBCCCCBBAA" ; 1.显示数据库列表.show d ...

  4. 初探 FFT/DFT

    有用的学习链接&书籍 傅立叶变化-维基百科 离散傅立叶变化-维基百科·长整数与多项式乘法 维基百科看英文的更多内容&有趣的图 快速傅立叶变化-百度百科,注意其中的图! 组合数学(第4版 ...

  5. BNU Questions and answers

    http://www.bnuoj.com/bnuoj/problem_show.php?pid=2490 这个题是先输入一个整数n,说明有几个数据,然后输入n个整数,然后用三个#分开,后面输入整数k, ...

  6. easyUI相关知识

    $("#sportGroupInfoDialog").dialog("open");//打开一个对话框,设置这个对话框的的布局方式 $('#sportGroup ...

  7. 监听手机晃动(摇一摇)SensorEventListener

    import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; ...

  8. oncreate 测量尺寸

    在android中,在oncreate里面只是将布局信息设置好,并没有进行布局,因此是没法进行测量view或者屏幕的长高,可以通过下面的observer来观察,当view布局完成之后会回调下面的两个接 ...

  9. ASP.NET Core 中文文档

    ASP.NET Core 中文文档 翻译计划 五月中旬 .NET Core RC2 如期发布,我们遂决定翻译 ASP.NET Core 文档.我们在 何镇汐先生. 悲梦先生. 张仁建先生和 雷欧纳德先 ...

  10. Qt生成灰度图(转载)

    Qt生成灰度图(转载)   项目中用到大量基础图像处理知识,其中灰度图的生成是很重要的一环. 先补充一些基础知识: ------------------------------------------ ...