KMP模板及总结
KMP是一种字符串匹配算法,它在时间复杂度上较暴力匹配算法由很大的优势。比如我要找字符串S中是否存在子串P,如果暴力匹配的话,则时间复杂度为O(n*m),而kmp算法时间复杂度为O(n+m)。
这里我们有一个辅助的数组next[](先别管怎么求出来的),next[i]含义是模式串P中[0....i-1]这一段的长度小于这段字符串的长度的最长公共前缀(比如ababa,公共前缀就是aba)。
好,那我们接下来讲一下kmp算法的具体操作:
假设,我们开始有字符串S:ababaaba 模式串P:abaa
对应next[i](0=<i<=len(P))的值为:
next[0]=-1 (无)
next[1]=0 (a)
next[2]=0 (ab)
next[3]=1 (aba)
next[4]=1 (abaa)
好,有了next数组,我们接下来进行匹配,设i=0是S上的当前匹配位置,j=0是P上的当前匹配位置。
第一次匹配,一直到i=3,j=3时匹配失败,令j=nxet[j]继续匹配。(为什么可以令j=next[j]?简单来说P[0...0]等于P[2...2],而通过第一次匹配,我们知道P[2..2]等于S[2...2],所以可以跳过这一段不用重复匹配,具体原理接下来解释)
第二次匹配,从i=3,j=1开始,匹配成功,获得答案。
大概过程就是这样。
下面按我自己的理解,解释一下kmp的原理:
如下图所示(图很丑,我真的不知道怎么画图),S[0...i]和P[0...i]匹配上了,匹配到i+1时匹配失败。

好,我们仔细分析一下,设L=nxet[i+1],则P[0...L]等于P[i-L...i],又因为通过刚才的匹配,我们确定了S[0...i]等于P[0...i],所以在S上也有一段对应的S[L-i...i]=P[L-i..i]=P[0...L]。
所以第二次匹配时,我们可以直接将P挪动,使P[0...L]对应S[L-i...i],直接从i+1开始匹配(即上文中的j=next[j]),如下图所示:

P[0...L]=S[L-i..i]可以理解,但是为什么可以直接挪过来呢,忽略了可能出现的情况怎么办?比如说下图这样的情况:

是否会有一段这样的字符串S[k..k+m]被我们忽略呢?若有的话,那显然k的位置更优因为i-k>L更有利于我们减少重复匹配。
实际上是不存在的,很容易知道,若存在一段长度大于L的S[k...i]=P[0...i-k+1]那么因为P[0...i]=S[0...i]肯定会有一段P[k..i]=S[k..i]=P[0..i-k+1],即P[0...i-k+1]和P[k..i]是一段公共前缀。
但是前面我们说了L=next[i+1]表示P[0...i]的最长公共前后缀,而上述的情况存在则说明有比L更长的公共前缀,这就矛盾了,所以S[k...k+m]这样的字符串是不存在的。
好了,这下kmp的原理我们知道了,接下来说next数组是如何构造的:
其实求next数组相当于模式串P自己跟自己做kmp,然后将最大的匹配结果记录在对应位置,所以实际上求next数组的代码跟kmp是几乎一样的。
模板代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=1e6+; int nxt[M];
char s[M],p[M]; //获得next数组
void getnext(char *p,int len){
int i,j;
i=,j=nxt[]=-;
while(i<len){
while(j!=-&&p[i]!=p[j]) j=nxt[j];
nxt[++i]=++j;
}
}
//返回p在s中第一次出现的位置
void kmp(char *s,char *p){
int len1,len2,i,j;
i=j=;
len1=strlen(s);
len2=strlen(p);
getnext(p,len2);
while(i<len1){
while(j!=-&&s[i]!=p[j]) j=nxt[j];
i++,j++;
if(j==len2)
return i-len2+;
}
return -;
}
KMP常见题型:
一、字符串匹配,求出模式串P在S中是否存在,输出第一次出现的位置
二、求模式串P在S中的出现次数(注意分可重和不可重的情况)
三、求所有公共前后缀(既是前缀又是后缀)
四、求字符串循环节
五、求所有S的前缀在S中出现次数之和
六、最大最小表示
KMP模板及总结的更多相关文章
- hdu 1686 KMP模板
// hdu 1686 KMP模板 // 没啥好说的,KMP裸题,这里是MP模板 #include <cstdio> #include <iostream> #include ...
- Oulipo HDU 1686 KMP模板
题目大意:求模式串在主串中的出现次数. 题目思路:KMP模板题 #include<iostream> #include<algorithm> #include<cstri ...
- KMP模板(bin)
KMP模板 主要是kuangbin的模板,之后加了一点我的习惯和理解. kmpN() 作用:构造next数组 参数:模式串,模式串长度 kmpC() 作用:返回模式串在主串中出现的次数(可重复) 参数 ...
- HDU 1711 - Number Sequence - [KMP模板题]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711 Time Limit: 10000/5000 MS (Java/Others) Memory L ...
- HDU 1711 Number Sequence(KMP模板)
http://acm.hdu.edu.cn/showproblem.php?pid=1711 这道题就是一个KMP模板. #include<iostream> #include<cs ...
- 剪花布条---hdu2087(kmp模板)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 kmp模板题: #include <cstdio> #include <cst ...
- Oulipo----poj3461(kmp模板)
题目链接:http://poj.org/problem?id=3461 和 减花布条 的题对比一下: 求s2中s1的个数kmp模板: #include<stdio.h> #include& ...
- kmp模板 && 扩展kmp模板
kmp模板: #include <bits/stdc++.h> #define PB push_back #define MP make_pair using namespace std; ...
- kuangbin专题16B(kmp模板)
题目链接: https://vjudge.net/contest/70325#problem/B 题意: 输出模式串在主串中出现的次数 思路: kmp模板 在 kmp 函数中匹配成功计数加一, 再令 ...
- [HDU1711]KMP模板
解题关键:1.直接套kmp模板即可,注意最后输出的位置,需要在索引的位置+1. 2.next用作数组名在oj中会编译错误, 3.选用g++,只有g++才会接受bits/stdc++.h OJ中g++和 ...
随机推荐
- day4 数组学习
java提供的数组排序操作:java.util.Arrays.sort(数组名): java提供的数组复制:system.arraycopy(源数组名称,源数组开始点下标,目标数组名称,目标数组开始下 ...
- 科学计算三维可视化---Mlab基础(改变物体的外观颜色)
import numpy as np from mayavi import mlab #建立数据 x,y = np.mgrid[-::200j,-::200j] z = *np.sin(x*y)/(x ...
- seaborn基础整理
seaborn是基于matplotlib的更高级的做图工具,下面主要针对以下几个部分进行整理: 第一部分:https://douzujun.github.io/page/%E6%95%B0%E6%8D ...
- Swift动态添加UIImageView并添加事件
Swift动态添加UIImageView并添加事件: 1. 创建UIImageView实例,并进行初始化 2. 设置UIImageView的用户交互属性userInteractionEnabled为T ...
- IFrame跨域处理方法-Javascript
在漫长的前端开发旅途上,无可避免的会接触到ajax,而且一般情况下都是用在同一域下的ajax请求:但是如果请求是发生在不同的域下,请求就无法执行,并且会抛出异常提示不允许跨域请求,目前我没有找到明确的 ...
- 当python模式遇见cedet
TAG: emacs, python, cedet, semantic, ctags DATE: 2013-08-20 我用Emacs 24写python程序. 发现屏幕不时有些闪动,MiniBuff ...
- kafka入门(2)- 环境部署
部署Zookeeper(单机/集群) 1.下载安装文件: http://mirror.bit.edu.cn/apache/zookeeper/ 2.解压文件(本文解压到 D:\zookeeper-3. ...
- POJ 3255 Roadblocks (次短路 SPFA )
题目链接 Description Bessie has moved to a small farm and sometimes enjoys returning to visit one of her ...
- Java 8 Lambda表达式,让你的代码更简洁
Lambda表达式是Java 8一个非常重要的新特性.它像方法一样,利用很简单的语法来定义参数列表和方法体.目前Lambda表达式已经成为高级编程语言的标配,像Python,Swift等都已经支持La ...
- Java与JS生成二维码
1.二维码概念 二维码/二维条码是用某种特定的集合图形按一定规律在平面上(二维方向上)分布的黑白相间的图形记录数据符号信息的图片. 黑线是二进制的1,空白的地方是二进制的0,通过1.0这种数据组合用于 ...