KMP算法是一种改进的模式匹配算法,相比于朴素的模式匹配算法效率更高。下面讲解KMP算法的基本思想与实现。

  先来看一下朴素模式匹配算法的基本思想与实现。

  朴素模式匹配算法的基本思想是匹配过程中如果该位置相等,继续匹配各自的下一位,直至匹配完成,或者出现一位不匹配,如果该位置不相等,主串的匹配位置返回上次开始匹配位置的下一位,副串的匹配位置再次从头开始。

实现程序如下:

  主串s,副串t,如果存在,返回t在s中第一次出现的位置,否则返回-1。

 int Index(char *s,char *t){
int ls=strlen(s),lt=strlen(t);
int i=;//主串匹配位置
int j=;//副串匹配位置
while(i < ls && j < lt){
if(s[i] == t[j]){
i++;
j++;
}
else{
i=i-j+;
j=;
}
}
if(j >= lt)//副串匹配完成
return i-j;
else
return -;
}

  可以设想,最糟糕的情况是每次的匹配的不成功均发生在了最后一位匹配,那么它的时间就主要浪费在了主串回溯的过程,比如00000001(7个0)和001,就有5次回溯是不必要的,它浪费的时间是随着匹配成功之间的0的个数增多而增多,自然就想到没有什么办法去解决这个问题呢?

  下面就轮到KMP算法登场了。

  为了解决每次主串匹配不成功尽可能的往右边滑的更远一点问题,自然想到充分利用现在已知的信息,这里借鉴《算法竞赛入门经典 训练指南》中的图解,具体体会一下KMP算法的精髓。

  假如现在正在匹配主串中*位置和副串abbaaba的最后一个字符,发现二者不同(称为失配),这时,朴素算法的做法是将串的开头放在!!的位置上重新开始匹配,但KMP算法为了让副串尽可能的回溯少一点,就利用现在已知的全部副串的信息来构建一个发现失配后副串尽可能的往右滑的更远的状态转移图,例如根据之前的匹配,我们知道了主串中*之前的副串长度的字符串,因为到*的时候才失配,我们可以知道副串右移一位、右移两位甚至三位都是不行的,因为和自己匹配失败,但是右移四位的时候就可能和后面的匹配了。这个右移的比较过程实际上就是一个串的前缀和后缀匹配的过程,为了滑的更远,我们需要找到两者最大的相似度,我们发现当走到副串的最后一个位置发现不匹配时前面的串的前后缀最大相似度是2,也就是ab的长度,故图中可以看到当最后一个字符失配的时候下面的实体黑线指向了2,就完成了往右滑的尽可能远的任务。

  那么怎么计算一个子串的前后缀的相似度呢?

  我们用next[j]数组来表示j下次应该返回的位置,函数定义如下:

  next[j]=   0,当j=0

      max({k|0<k<=j,且p0...pk=p(j-k)...pj},当此集合不为空

      1,其他

算法实现如下:

  副串t,用next数组存储结果。

 void get_next(char t[],int next[])
{
int l=strlen(t);
int i=;//副串匹配位置
int j=-;//next数组位置指针,初始化为-1,表示回溯边界
next[]=-;//0表示长度为0的子串的前后缀相似度为-1,也表示回溯边界
while(i < l){
if(j == - || t[i] == t[j]){
i++;
j++;
next[i]=j;
}
else
j=next[j];
}
}

下面将制作好的next数组应用到KMP算法中。

代码如下:

 int Index_KMP(char *s,char *t){
int ls=strlen(s),lt=strlen(t);
int i=;//主串起始匹配位置
int j=;//副串起始匹配位置
int next[maxn]={};
get_next(t,next);
while(i < ls && j < lt){
if(j == - || s[i] == t[j]){//增加j==-1表示回溯到了边界的情况
i++;
j++;
}
else{
j=next[j];//j返回到合适的位置,而i不用改变
}
}
if(j >= lt)//匹配完成
return i-j;
else
return -;
}

  可以看到KMP算法相较朴素的模式匹配算法,多了制作next数组,多了一个判断条件,就成功的避免了主串不必要的回溯,节省了时间。下面给出几道练习题目,巩固知识。

  1.简单的模板题HDU 1711 Number Sequence

  https://www.cnblogs.com/wenzhixin/p/7345115.html

  2.需要一点思维转换HDU 2203 亲和串

  https://www.cnblogs.com/wenzhixin/p/7344076.html

  3.加深印象HDU 3746 Cyclic Nacklace

  https://www.cnblogs.com/wenzhixin/p/7345115.html

  其他练习参考右侧分类中的KMP。

KMP算法(——模板习题与总结)的更多相关文章

  1. hdu 1711 KMP算法模板题

    题意:给你两个串,问你第二个串是从第一个串的什么位置開始全然匹配的? kmp裸题,复杂度O(n+m). 当一个字符串以0为起始下标时.next[i]能够描写叙述为"不为自身的最大首尾反复子串 ...

  2. DFS算法(——模板习题与总结)

    首先,需要说明的是搜索算法本质上也是枚举的一种,时间复杂度还是很高的,遇到问题(特别是有水平的比赛上),不要优先使用搜索算法. 这里总结一下DFS算法: 1.从图中某个顶点出发,访问v. 2.找出刚访 ...

  3. KMP算法模板&&扩展

    很不错的学习链接:https://blog.csdn.net/v_july_v/article/details/7041827 具体思路就看上面的链接就行了,这里只放几个常用的模板 问题描述: 给出字 ...

  4. kmp算法模板及理解

    kmp算法是复杂度为O(n+m)的字符串匹配算法; 首先kmp算法的核心是在模式串中获得next数组,这个数组表示模式串的子串的前缀和后缀相同的最长长度; 这样在匹配的过程中如果指到不匹配的位置,模式 ...

  5. 【Luogu P3375】字符串匹配KMP算法模板

    Luogu P3375 模式串:即题目中的S2所代表的意义 文本串:即题目中的S1所代表的意义 对于字符串匹配,有一种很显然的朴素算法:在S1中枚举起点一位一位匹配,失配之后起点往后移动一位,从头开始 ...

  6. POJ 3461 Oulipo KMP算法(模板)

    题意: 给两组字符串a和b,求a在b中出现的次数 关于KMP: 马拉车算法是处理回文串,而KMP是处理前后缀的相同字符串的最长长度. a | a | b | a | a | f | a | a 数组 ...

  7. Kmp 算法模板 C

    /** * name:KMP * time:2012-11-22 * 字符串快速匹配 */ #include<stdio.h> #include<string.h> typed ...

  8. KMP算法模板

    不懂的话推荐看这篇博客,讲的很清楚 http://blog.csdn.net/v_july_v/article/details/7041827 #include<iostream> #in ...

  9. KMP算法———模板

    做出KMP字符串匹配算法心情也是好好哒,萌萌哒. 感谢黄学长,感谢栋栋! #include<cstdio>#include<string>#include<iostrea ...

  10. kmp算法 模板

    #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #inclu ...

随机推荐

  1. bootstrap手风琴折叠

    <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...

  2. DXP中插入LOGO图片方法(1)

    DXP中插入LOGO图片方法 1.QQ截图后,打开“开始”-->"附件"——>"画图工具",如图: 2.另存为BMP文件格式(设置图片大小.黑白色即 ...

  3. ASP.NET中实现回调

    一.引言 在ASp.NET网页的默认模型中,用户通过单击按钮或其他操作的方式来提交页面,此时客户端将当前页面表单中的所有数据(包括一些自动生成的隐藏域)都提交到服务器端,服务器将重新实例化一个当前页面 ...

  4. 利用CPaintDC::IntersectClipRect将绘图限制在局部区域

    问题背景:画带坐标的图,例如 画里面那条曲线的时候,希望将绘图区域局限在坐标范围内,范围外的就自动屏蔽掉. 两个方案,一是用CPaintDC的SelectClipRgn函数,感觉略麻烦.另一个函数,就 ...

  5. [翻译]第二天 - Visual Studio 中的 .NET Core 模版一览

    原文: http://michaelcrump.net/part2-aspnetcore/ 免责声明:我不是 .NET Core 开发团队的一员,并且使用的是公开.可用的工具. 简介 该系列文章的完整 ...

  6. WPF学习笔记(4):获取DataGridTemplateColumn模板定义的内容控件

    在之前的DataGrid的DataGridTemplateColumn列中,自定义了一个TextBox控件,但是在C#代码中提示找不到这个控件,导致无法对该控件进行操作.在网上搜索后,发现一些处理方法 ...

  7. mysql添加外键的4种方式

    今天开始复习,在过后的几天里开始在博客上记录一下平时疏忽的知识点,温故而知新 屁话不多--直接上货 创建主表: 班级 CREATE TABLE class(cid INT PRIMARY KEY AU ...

  8. mongodb批量更新某个字段

    查询出hospitalName是xx医院和openId以2开头的所有记录,并且更新my_booking表中的payType为1. db.getCollection('my_booking').find ...

  9. 【bug】VUE:Cannot read property '_withTask' of undefined

    如题 成因:极大可能是template上有某个函数,没有在 methods中声明导致的. 解决:找到那个未声明的函数名,写在methods中.你可以使用二分法快速找到.

  10. Linux - 针对用户账号的常用操作

    用户目录 除root用户外,其他默认的用户目录一般为/home/<user name>. 可以通过如下步骤修改默认用户目录 修改/etc/passwd文件中相应用户的路径信息 停止此用户的 ...