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. docker mac

    官网上有安装方法.已安装成功. 容器千万不能随便删 现在已经不用boot2docker,使用dockertools来安装docker,dockertools中包含docker-machine,等等. ...

  2. Ajax登录用户名密码

    <script src="http://code.jquery.com/jquery-latest.js"></script>#引入jQuery#当点击函数 ...

  3. Apache中 RewriteCond 规则参数介绍

    RewriteCond指令定义了规则生效的条件,即在一个RewriteRule指令之前可以有一个或多个RewriteCond指令.条件之后的重写规则仅在当前URI与Pattern匹配并且满足此处的条件 ...

  4. C#生成指定长度随机数

    public static string GetRandomString(int iLength) { ";// 随机字符中也可以为汉字(任何) StringBuilder sb = new ...

  5. 一、winForm-DataGridView操作——控件绑定事件的两种方法

    在winForm窗体中绑定(注册)事件的方法有两种: 一.绑定事件 双击控件,即进入.cs的代码编辑页面,会出现 类似于“ private void 控件名称_Click(object sender, ...

  6. BZOJ 1011--[HNOI2008]遥远的行星(乱搞)

    1011: [HNOI2008]遥远的行星 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 5684  Solved ...

  7. 暴破助攻提权:ruadmin

    i春秋作家:yangyangwithgnu 1 缘由 千辛万苦拿下的 webshell 不是 www-data 用户就是 networkservice 权限,要想拓展攻击面.扩大战果,提权,是必经之路 ...

  8. 使用命令行工具npm新创建一个vue项目

    使用vue开发项目的前期工作可以参考前面写的:  Vue环境搭建及node安装过程整理 Vue.js 提供一个官方命令行工具,可用于快速搭建大型单页应用.该工具提供开箱即用的构建工具配置,带来现代化的 ...

  9. sync.WaitGroup和sync.Once

    sync.WaitGroup,顾名思义,等待一组goroutinue运行完毕.sync.WaitGroup声明后即可使用,它有如下方法: func (wg *WaitGroup) Add(delta ...

  10. python--使用pickle序列化对象

    pickle序列化对象 如果希望透明地存储 Python 对象,而不丢失其身份和类型等信息,则需要某种形式的对象序列化:它是一个将任意复杂的对象转成对象的文本或二进制表示的过程. 同样,必须能够将对象 ...