【説明する】KMP
KMP是一个困扰我很久的算法,听老师或者是学姐讲了差不多有4次了,但是还是搞不太懂,今天终于,终于,终于搞懂了!
——2017-10-29 Vanora
首先推荐一下KMP详解——July
读罢之后内心只有一个感觉:我的KMP终于可以毕业了qwq
学东西千万不要求快!细细地,慢慢地去读这篇文章,相信你也可以从头到尾彻底理解KMP算法呦~
接下来是一些KMP的练手题:
做完这些并且真正搞懂之后,相信你一定就会KMP算法了~(一定要理解了,吃透了!)
1.P3375 【模板】KMP字符串匹配
直通车
思路:
真正意义上的KMP板子题,很良心(不加优化版)
新知识Get!!!:
char数组不清零,直接用cin读入的话,自动清零!!!好厉害的样子!!!
坑点:
一定要真正理解nxt[]求得到底是什么,是用匹配串求解还是用文本串
上代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; const int M = ;
char s[M],p[M];
int lens,lenp; int nxt[M];
void getnxt() {
int k=-,j=;
nxt[]=-;
while(j<lenp) {
if(k==- || p[j]==p[k]) {
j++;k++;
nxt[j]=k; //记录更新的nxt值
}
else k=nxt[k];
}
} void KMP() {
int i=,j=;
while(i<lens) {
if(j==- || s[i]==p[j]) i++,j++;
//j==-1:没有nxt,所以从一开始进行匹配
//s[i]==p[j]:当前文本串与匹配串的位置上的字符匹配成功,继续匹配
else j=nxt[j]; //寻找更短的公共前后缀
if(j==lenp) {
printf("%d\n",i-lenp+);
i--; //文本串之前已经匹配过了,所以没有再次进行匹配的需要了
j=; //匹配串从新开始进行匹配
}
}
} int main() {
cin>>s>>p;
lens=strlen(s);
lenp=strlen(p);
getnxt();
KMP();
for(int i=; i<=lenp; i++) printf("%d ",nxt[i]);
return ;
}
2.POJ 3461 Oulipo
直通车
思路:
坑点:
上代码:
1)while版(mine)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; const int M = ;
const int N = ;
char s[M],p[N];
int T,ans,lens,lenp; int nxt[N];
void getnxt() {
int k=,j=;
nxt[]=-;nxt[]=;
while(j<lenp) {
if(k==- || p[j]==p[k]) {
k++,j++;
nxt[j]=k;
}
else k=nxt[k];
}
} void KMP() {
int i=,j=;
while(i<lens) {
if(s[i]==p[j]) i++,j++;
else if(j>=) j=nxt[j];
else i++,j=;
if(j==lenp) ans++,j=nxt[j];
}
} int main() {
scanf("%d",&T);
while(T--) {
scanf("%s%s",p,s);
lens=strlen(s);
lenp=strlen(p);
getnxt();
KMP();
printf("%d\n",ans);
ans=;
}
return ;
}
2)从网上学到的另外一种方法,感觉十分类似,然而能AC。。。服气。。。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; const int M = ;
const int N = ;
char s[M],p[N];
int ans,lens,lenp; int nxt[N];
void getnxt() {
int k=,j;
nxt[]=-;nxt[]=;
for(j=; j<=lenp; j++) {
while(k>= && p[k]!=p[j-]) k=nxt[k];
nxt[j]=++k;
}
} void KMP() {
int i=,j=;
while(i<lens) {
if(s[i]==p[j]) i++,j++;
else if(j>=) j=nxt[j];
else i++,j=;
if(j==lenp) ans++,j=nxt[j];
}
} int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%s%s",p,s);
lens=strlen(s);
lenp=strlen(p);
getnxt();
KMP();
printf("%d\n",ans);
ans=;
}
return ;
}
3)采用for循环的一种方法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; const int M = ;
const int N = ;
int T,ans,lens,lenp;
char s[M],p[N]; int nxt[N];
void getnxt() {
nxt[]=;
for(int i=; i<lenp; i++) {
int j=nxt[i];
while(j && p[i]!=p[j]) j=nxt[j];
nxt[i+] = p[i]==p[j] ? j+ : ;
}
} void KMP() {
int j=;
for(int i=; i<lens; i++) {
while(j && (p[j]!=s[i])) j=nxt[j];
if(p[j]==s[i]) j++;
if(j==lenp) ans++;
}
} int main() {
scanf("%d",&T);
while(T--) {
memset(nxt,,sizeof(nxt));
ans=;
scanf("%s%s",p,s);
lenp=strlen(p);
lens=strlen(s);
getnxt();
KMP();
printf("%d\n",ans);
}
return ;
}
3.P1308 统计单词数
直通车
思路:
①因为会出现空格,所以手动将s,p的左右均+' ',然后再进行KMP即可
②不需要+' ',直接在KMP匹配成功之后判断是否s左右均拥有' '即可
不过需要注意的是:当在一开头就匹配成功的时候则只需要判断是否s右边有' '即可
坑点:
千万不要用gets进行输入,会编译错误。。。。
上代码:
①
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std; const int pl = ;
int lens,lenp,ans=-,firsta=-;
string s,p; int nxt[pl];
void getnxt() {
int k=,j=;
nxt[]=-,nxt[]=;
while(j<lenp) {
if(k==- || p[k]==p[j]) {
k++,j++;
nxt[j]=k;
}
else k=nxt[k];
}
} void KMP() {
int i=,j=;
while(i<lens) {
if(s[i]==p[j]) i++,j++;
else if(j>=) j=nxt[j];
else i++,j=;
if(j==lenp) {
if(firsta==-) firsta=i-j;
ans++,j=nxt[j];
}
}
} void tochange(string &a,int len) {
for(int i=; i<len; i++) {
if(a[i]==' ') continue;
int x=a[i]-'A';
if(x>=) x-=;
char y=x+'a';
a[i]=y;
}
} int main() {
getline(cin,p);
p=' '+p+' ';
lenp=p.length();
tochange(p,lenp);
getline(cin,s);
s=' '+s+' ';
lens=s.length();
tochange(s,lens);
getnxt();
KMP();
if(ans==-) printf("%d",ans);
else printf("%d %d",ans+,firsta);
return ;
}
②
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std; const int pl = ;
int lens,lenp,ans=-,firsta=-;
string s,p; int nxt[pl];
void getnxt() {
int k=,j=;
nxt[]=-,nxt[]=;
while(j<lenp) {
if(k==- || p[k]==p[j]) {
k++,j++;
nxt[j]=k;
}
else k=nxt[k];
}
} void KMP() {
int i=,j=;
while(i<lens) {
if(s[i]==p[j]) i++,j++;
else if(j>=) j=nxt[j];
else i++,j=;
if(j==lenp && s[i]==' ') {
if(i>j && s[i-j-]==' ') {
if(firsta==-) firsta=i-j;
ans++,j=nxt[j];
} else {
if(i==j) {
// if(i==0) { //等价
if(firsta==-) firsta=i-j;
ans++,j=nxt[j];
}
}
}
}
} void tochange(string &a,int len) {
for(int i=; i<len; i++) {
if(a[i]==' ') continue;
int x=a[i]-'A';
if(x>=) x-=;
char y=x+'a';
a[i]=y;
}
} int main() {
getline(cin,p);
lenp=p.length();
tochange(p,lenp);
getline(cin,s);
lens=s.length();
tochange(s,lens);
getnxt();
KMP();
if(ans==-) printf("%d",ans);
else printf("%d %d",ans+,firsta);
return ;
}
【説明する】KMP的更多相关文章
- POJOの説明
参考URL: https://baike.baidu.com/item/POJO/3311958?fr=aladdin https://wenku.baidu.com/view/eba89bbcf12 ...
- 【説明する】hash
首先对于判重,我们能想到的方法有什么呢? 1)bool数组 2)set(集) 数组与集合的优缺点: 1.因为集合是对数组做的封装,所以,数组永远比任何一个集合要快. 2.数组声明了它容纳的元素的类型, ...
- 【説明する】DS
其实就是数据结构课后题整理....只会一个是什么鬼 染色问题: 线段树? 功能太强大了! 我们并不需要那么多的功能 运用并查集!!! 将相同的并为一段 BZOJ 2375(讲真我没找到这个题在哪里.. ...
- 【説明する】STL
作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的. STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现. 所以今天要整理的东西就是STL!(orz 杨 ...
- UbuntuでPostgreSQLをインストールからリモートアクセスまでの手順
PostgreSQLサーバの立ち上げに少しハマりましたので.メモしておきます. OS: Ubuntu14.04 LTS インストール 最初はPostgreSQLをインストールします.普通にapt-ge ...
- VirtualBox 共享文件夾
説明:host為window10,guest為centos7 一.安装VBoxLinuxAdditions 1. 在guest上挂载virtualbox安装目录下的VBoxGuestAdditions ...
- Ruby中字符串与正则表达式的问题
Ruby的正则表达式为Regexp类的对象 主要的元语言字符 記号 意味 例 説明 ^ 行頭 /^abc/ abcで始まる行 $ 行末 /abc$/ abcで終わる行 . 任意の1文字 /a.b/ a ...
- WebMidiLink
g200kg > WebMidiLink > 1.Introduction WebMidiLink 2012/06/26 1.Introduction « Prev 1.Introduct ...
- xpath 参考
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Te ...
随机推荐
- JS OOP 概述
JS面向对象,大致内容 1.面向对象的基础 2.深入认识JS的函数 3.JS类的实现 4JS中共有成员,私有成员和静态成员 5.JS的反射 6.JS的继承 7.JS实现抽象类 8.JS事件设计模式 9 ...
- Asp.net core中间件实现原理及用法解说
简述asp.net core中间件的实现思路 原文地址:https://www.cnblogs.com/shengyu-kmust/p/11583974.html 一次http请求的过程,就是对一个R ...
- regarding-hsts-in-netscaler
regarding-hsts-in-netscaler 参考: Strict Transport Security (STS or HSTS) with Citrix NetScaler and Ac ...
- Linux 命令实战
命令登录 ssh UserName@RemoteIP ssh seemmo@192.168.0.1 统计文件.目录的数量 统计当前目录下文件数量:ls -l | grep "^- ...
- pytorch自定义网络层以及损失函数
转自:https://blog.csdn.net/dss_dssssd/article/details/82977170 https://blog.csdn.net/dss_dssssd/articl ...
- svg-sprite-loader ( svg-icon) 使用
svg-sprite-loader 可以多个svg图标合并. 使用时只需根据合并的symbol的id即可. <svg class="svg-icon" aria-hidde ...
- mycat 报错 java.lang.OutOfMemoryError: Java heap space
今天排查mysql的错误日志发现 wrapper.log 中有如下错误日志 INFO | jvm 1 | 2019/10/20 12:52:31 | java.lang.OutOfMem ...
- Java 之 泛型
一.泛型概述 集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成 Object 类型.当我们取出一个对象,并且进行相应的操作,这时必须采用类型转换. 先观察下面代码: publ ...
- Android开发之图像处理那点事——滤镜
在Android开发中,一般对图像的处理就是Bitmap(位图),它包含了图像的全部数据,即点阵和颜色值,点阵就是包含像素点的矩阵,而颜色值就是ARGB,分别代表透明.红色.绿色.蓝色通道,它们共同决 ...
- gcc和g++编译器
.c文件,gcc当做c语言处理 .cpp文件,gcc和g++当做c++处理 .c文件和.cpp文件编译时,都是使用的gcc编译器 .cpp使用gcc链接,需要加入-lstdc++选项 举例 #incl ...