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. [zjoi2010]cheese

    题目: 贪吃的老鼠(cheese.c/cpp/pas/in/out) 时限:每个测试点10秒 [问题描述] 奶酪店里最近出现了m只老鼠!它们的目标就是把生产出来的所有奶酪都吃掉.奶酪店中一天会生产n块 ...

  2. 分形之谢尔宾斯基(Sierpinski)四面体

    前面讲了谢尔宾斯基三角形,这一节的将对二维三角形扩展到三维,变成四面体.即将一个正四面体不停地拆分,每个正四面体可以拆分成四个小号的正四面体.由二维转变到三维实现起来麻烦了许多.三维的谢尔宾斯基四面体 ...

  3. Ocelot——初识基于.Net Core的API网关

    前言 前不久看到一篇<.NET Core 在腾讯财付通的企业级应用开发实践>,给现在研究.Net Core及想往微服务方向发展的人来了一剂强心针.于是我也就立刻去下Ocelot的源码及去阅 ...

  4. Hive Bug修复:ORC表中array数据类型长度超过1024报异常

    目前HVIE里查询如下语句报错: select * from dw.ticket_user_mtime limit 10; 错误如下: 17/07/06 16:45:38 [main]: DEBUG ...

  5. SQL SERVER的锁机制(四)——概述(各种事务隔离级别发生的影响)

    六.各种事务隔离级别发生的影响 修改数据的用户会影响同时读取或修改相同数据的其他用户.即这些用户可以并发访问数据.如果数据存储系统没有并发控制,则用户可能会看到以下负面影响: · 未提交的依赖关系(脏 ...

  6. SignalR2结合ujtopo实现拓扑图动态变化

    上一篇文章基于jTopo的拓扑图设计工具库ujtopo,介绍了拓扑设计工具,这一篇我们使用SignalR2结合ujtopo实现拓扑图的动态变化. 仅仅作为演示,之前的文章SignalR2简易数据看板演 ...

  7. 【文文殿下】[CEOI2004]锯木厂选址 题解

    题解 我们枚举建厂的位置,发现有个\(n^2\)的DP.随手搞个斜率优化到\(O(n)\). #include<bits/stdc++.h> using namespace std; ty ...

  8. Django(ORM查询1)

    day69 参考:http://www.cnblogs.com/liwenzhou/p/8660826.html 在Python脚本中调用Django环境 orm1.py import os if _ ...

  9. underscore.js源码研究(1)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  10. 如何执行超过一百兆(100MB)的sql脚本?

    最近遇到一个问题,在sqlserver的查询分析器里面执行一个超过100MB的数据库脚本,发现老是报“引发类型为“System.OutOfMemoryException”的异常”,上网查了一下,主要是 ...