[一本通学习笔记] KMP算法
KMP算法
对于串s[1..n],我们定义fail[i]表示以串s[1..i]的最长公共真前后缀。
我们首先考虑对于模式串p,如何计算出它的fail数组。定义fail[0]=-1。
- 根据“真前后缀”的条件,容易得到fail[1]=0
- 对于任意的i>1,显然在s[fail[i-1]+1]==s[i]的时候,我们有fail[i]=fail[i-1]
- 如果s[fail[i-1]+1]!=s[i],那么我们需要去尝试s[fail[fail[i-1]]+1]是否与s[i]相等,否则再继续下去。
这是因为我们最终要找的是s[1..i]的最长公共前后缀,如果它不是由s[1..i-1]的最长公共前后缀扩增而来,那么它一定是由s[1..fail[i-1]]的最长公共前后缀扩增而来。毕竟,最长公共前后缀包含了若干个公共前后缀。即s[1..fail[i-1]]的最长公共前后缀也是s[1..i-1]的一个公共前后缀,虽然它未必最长。
// Build fail array for pattern string
for(int i=;i<=m;i++) {
fail[i]=fail[i-];
while(p[fail[i]+]-p[i] && fail[i]) fail[i]=fail[fail[i]];
if(p[fail[i]+]==p[i]) ++fail[i];
}
fail[0]=-1;
预处理完毕后,匹配过程与其大同小异。
我们需要定义两个指针i,j,指向当前希望要匹配的两个字符。
如果s[i]!=p[j],则需要将模式串向右滑移,即j=fail[j-1]+1。当然如果j=0了,则重设j=1,并将模式串起点向右移动一位。
如果s[i]==p[j],当模式串没有匹配完全即j<m时,将两个指针同时向右移动即可。如果匹配完了,则报告一个结果,并将模式串按j=fail[j-1]+1进行滑移,以便于进行下一次匹配。
for(int i=,j=;i<=n;) {
if(s[i]==p[j]) {
if(j<m) ++i,++j;
else {
cout<<i-m+<<endl;
j=fail[j-]+;
}
}
else {
j=fail[j-]+;
if(j<=) j=,i++;
}
}
算法总体复杂度O(n+m)。
完整模板:
#include <bits/stdc++.h>
using namespace std; char s[],p[];
int n,m,fail[]; int main() {
ios::sync_with_stdio(false);
cin>>s+>>p+;
n=strlen(s+); m=strlen(p+);
// Build fail array for pattern string
for(int i=;i<=m;i++) {
fail[i]=fail[i-];
while(p[fail[i]+]-p[i] && fail[i]) fail[i]=fail[fail[i]];
if(p[fail[i]+]==p[i]) ++fail[i];
} fail[]=-;
for(int i=,j=;i<=n;) {
if(s[i]==p[j]) {
if(j<m) ++i,++j;
else {
cout<<i-m+<<endl;
j=fail[j-]+;
}
}
else {
j=fail[j-]+;
if(j<=) j=,i++;
}
}
for(int i=;i<=m;i++) cout<<(fail[i]<?:fail[i])<<" ";
cout<<endl;
}
#10046. 「一本通 2.2 练习 2」OKR-Periods of Words
容易发现这里我们要的其实是每个前缀减去最短的Border。类似并查集一样路径压缩一下即可。需要注意一些细节防止死循环。
#include <bits/stdc++.h>
using namespace std; char s[], p[];
int n, m, fail[]; int main() {
ios::sync_with_stdio(false);
cin >> m;
cin >> p + ;
// Build fail array for pattern string
long long ans = ;
fail[] = ;
for (int i = ; i <= m; i++) {
fail[i] = fail[i - ];
while (p[fail[i] + ] - p[i] && fail[i]) fail[i] = fail[fail[i]];
if (p[fail[i] + ] == p[i])
++fail[i];
}
fail[] = -;
for (int i = ; i <= m; i++) {
int j = i;
while (fail[j] > ) j = fail[j];
ans += i - j;
if (fail[i])
fail[i] = j;
}
cout << ans << endl;
}
#10047. 「一本通 2.2 练习 3」似乎在梦中见过的样子
#include <bits/stdc++.h>
using namespace std; char s[],p[];
int n,m,k,fail[],f[];
long long ans = ; int main() {
ios::sync_with_stdio(false);
cin>>p+>>k;
m=strlen(p+);
while(m) {
for(int i=;i<=m;i++) {
fail[i]=fail[i-];
while(p[fail[i]+]-p[i] && fail[i]) fail[i]=fail[fail[i]];
if(p[fail[i]+]==p[i]) ++fail[i];
if(f[fail[i]]) f[i]=f[fail[i]];
else if(fail[i]>=k) f[i]=fail[i];
else f[i]=;
if(f[i] && (f[i]*)<i) ++ans;
}
--m;
for(int i=;i<=m;i++) p[i]=p[i+];
memset(fail,,sizeof fail);
memset(f,,sizeof f);
}
cout<<ans<<endl;
}
#10048. 「一本通 2.2 练习 4」Censoring
搞个栈记录输出,顺便存下每个被输出点匹配到模式串的哪个位置
这样如果匹配就弹掉栈顶几个,并读取新栈顶原先匹配到了哪个位置,接下去匹配即可
#include <bits/stdc++.h>
using namespace std; char s[],p[];
int n,m,fail[],sta[],staj[],top; int main() {
ios::sync_with_stdio(false);
cin>>s+>>p+; n=strlen(s+); m=strlen(p+);
for(int i=;i<=m;i++) {
fail[i]=fail[i-];
while(p[fail[i]+]-p[i] && fail[i]) fail[i]=fail[fail[i]];
if(p[fail[i]+]==p[i]) ++fail[i];
} fail[]=-;
for(int i=,j=;i<=n;) {
if(s[i]==p[j]) {
if(j<m) ++top,sta[top]=i,staj[top]=j,++i,++j;
else top-=m-,j=staj[top]+,++i;
}
else {
j=fail[j-]+;
if(j<=) ++top,sta[top]=i,staj[top]=j,i++;
}
}
for(int i=;i<=top;i++) cout<<s[sta[i]];
cout<<endl;
}
#include <bits/stdc++.h>using namespace std;
char s[100005],p[100005];int n,m,k,fail[100005],f[100005];long long ans = 0;
int main() {ios::sync_with_stdio(false);cin>>p+1>>k;m=strlen(p+1);while(m) { for(int i=2;i<=m;i++) { fail[i]=fail[i-1]; while(p[fail[i]+1]-p[i] && fail[i]) fail[i]=fail[fail[i]]; if(p[fail[i]+1]==p[i]) ++fail[i]; if(f[fail[i]]) f[i]=f[fail[i]]; else if(fail[i]>=k) f[i]=fail[i]; else f[i]=0; if(f[i] && (f[i]*2)<i) ++ans; } --m; for(int i=1;i<=m;i++) p[i]=p[i+1]; memset(fail,0,sizeof fail); memset(f,0,sizeof f);}cout<<ans<<endl;}
[一本通学习笔记] KMP算法的更多相关文章
- 学习笔记-KMP算法
按照学习计划和TimeMachine学长的推荐,学习了一下KMP算法. 昨晚晚自习下课前粗略的看了看,发现根本理解不了高端的next数组啊有木有,不过好在在今天系统的学习了之后感觉是有很大提升的了,起 ...
- [ML学习笔记] XGBoost算法
[ML学习笔记] XGBoost算法 回归树 决策树可用于分类和回归,分类的结果是离散值(类别),回归的结果是连续值(数值),但本质都是特征(feature)到结果/标签(label)之间的映射. 这 ...
- 学习笔记 - Manacher算法
Manacher算法 - 学习笔记 是从最近Codeforces的一场比赛了解到这个算法的~ 非常新奇,毕竟是第一次听说 \(O(n)\) 的回文串算法 我在 vjudge 上开了一个[练习],有兴趣 ...
- 算法笔记--KMP算法 && EXKMP算法
1.KMP算法 这个博客写的不错:http://www.cnblogs.com/SYCstudio/p/7194315.html 模板: next数组的求解,那个循环本质就是如果相同前后缀不能加上该位 ...
- 来去学习之---KMP算法--next计算过程
一.概述 KMP算法是一种字符串匹配算法,比如现有字符串 T:ABCDABCDABCDCABCDABCDE, P:ABCDABCDE P字符串对应的next值:[0,0,0,0,1,2,3,4,0] ...
- 学习笔记——EM算法
EM算法是一种迭代算法,用于含有隐变量(hidden variable)的概率模型参数的极大似然估计,或极大后验概率估计.EM算法的每次迭代由两步组成:E步,求期望(expectation):M步,求 ...
- 数据挖掘学习笔记--AdaBoost算法(一)
声明: 这篇笔记是自己对AdaBoost原理的一些理解,如果有错,还望指正,俯谢- 背景: AdaBoost算法,这个算法思路简单,但是论文真是各种晦涩啊-,以下是自己看了A Short Introd ...
- [一本通学习笔记] AC自动机
AC自动机可以看作是在Trie树上建立了fail指针,在这里可以看作fail链.如果u的fail链指向v,那么v的对应串一定是u对应串在所给定字符串集合的后缀集合中的最长的后缀. 我们考虑一下如何实现 ...
- Java学习笔记——排序算法之快速排序
会当凌绝顶,一览众山小. --望岳 如果说有哪个排序算法不能不会,那就是快速排序(Quick Sort)了 快速排序简单而高效,是最适合学习的进阶排序算法. 直接上代码: public class Q ...
随机推荐
- open xml 导出excel遇到的问题
我有一个需求:使用ajax 下载excel文件 结果:失败 原因:下载文件是通过浏览器解析二级制流下载的,而ajax返回的是文本 方法: 1.如果你下载不需要参数,那直接写个a标签链接到地址就行 2. ...
- 纪中10日T1 2313. 动态仙人掌
纪中10日 2313. 动态仙人掌 (File IO): input:dinosaur.in output:dinosaur.out 时间限制: 1500 ms 空间限制: 524288 KB 具 ...
- C语言二级选择题考点汇总-数据结构与算法-【考点一】 什么是算法
1.算法及其基本特征 算法是指对方案的准确描述,是解决问题的执行步骤. 算法不等于数学上的计算方法,也不等于程序.程序是算法的载体. 算法的基本特征如下: (1)可行性:步骤可实现,执行结果可达到 ...
- [51nod 1256] 乘法逆元 - exgcd
给出2个数M和N(M < N),且M与N互质,找出一个数K满足0 < K < N且K * M % N = 1,如果有多个满足条件的,输出最小的. Solution 用 EXGCD 求 ...
- JBPM4 学习笔记 转
关于JBPM工作流 2. JBPM jBPM,全称是Java Business Process Management,是一种基于J2EE的轻量级工作流管理系统.JBPM使用Hiberna ...
- phpcms抛出的二维数组转移到js,js中for....in遍历数组,用“.”连接来读出一维数组值
直切正题: 1.phpcms在模版中读出数组有很多中方法,如,{pc:content action="lists"}或{pc:get sql=""},经过{lo ...
- 面试官:说说TCP和UDP的区别和应用场景
原创文章首发于公众号:「码农富哥」,欢迎收藏和关注,如转载请注明出处! 上一篇聊完 一文彻底搞懂 TCP三次握手.四次挥手过程及原理 这次聊聊TCP和UDP的区别和场景 TCP/IP 中有两个具有代表 ...
- gulp常用插件之gulp-notify使用
更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-notify这是一款gulp通知插件. 更多使用文档请点击访问gulp-notify工具官网. 安装 一键安装不多解释 npm inst ...
- 曼孚科技:AI算法领域常用的39个术语(上)
算法是人工智能(AI)核心领域之一. 本文整理了算法领域常用的39个术语,希望可以帮助大家更好地理解这门学科. 1. Attention 机制 Attention的本质是从关注全部到关注重点.将有限 ...
- jsp环境搭建
jsp开发环境需要JDK与Tomcat,需先下载JDK组件与tomcat组件 JDK地址:https://www.oracle.com/technetwork/java/javase/download ...