【説明する】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 ...
随机推荐
- kettle工具的介绍和使用
kettle详解(数据抽取.转换.装载) 原文地址链接:https://blog.csdn.net/qq_35731570/article/details/71123413 一:下载路径 当你要学 ...
- Ubuntu部署ftp服务器
Ubuntu 16.04 FTP服务器安装及配置 FTP File Transfer Protocol文件传输协议,两台计算机传送文件的协议,客户端可以通过FTP命令从服务器下载,上传文件,修 ...
- 奇妙的算法【7】-贪婪算法-dp
问题1描述:[贪婪算法,Dijistra算法] ①有一只兔子要从一个N*N的二维矩阵方格中从上跳到下面: ②每次只能向左或向下,越过一个方格,跳到下一个方格中: ③被越过的方格中的数值,表示该兔子越过 ...
- JavaScript指定日期格式化
formatDataToString:function (dates, formats) { var o = { "M+": dates.getMonth() + 1, //月份 ...
- 将两个数组相同index的value合并成一个新的value组成一个新的数组
将两个数组相同index的value合并成一个新的value组成一个新的数组 前提: 这两个数组的长度相同 生成后的新数组长度也相同 返回值都是对象 把rows对象的key和value弄成两个数组, ...
- K2 BPM_K2受邀出席QAD 2019年亚太区用户大会_全业务流程管理专家
6月12-13日,K2受邀参加了以“云聚创新,智造未来”为主题的QAD 2019年亚太区用户大会.会议上K2同与会嘉宾们共商制造业数字化转型,就如何用流程赋能企业实现智能制造进行了精彩分享. 近期发布 ...
- [转]Spring Security Oauth2 认证流程
1.本文介绍的认证流程范围 本文主要对从用户发起获取token的请求(/oauth/token),到请求结束返回token中间经过的几个关键点进行说明. 2.认证会用到的相关请求 注:所有请求均为po ...
- Iterator 其实很简单(最好理解的工厂模式的例子)
我们都知道Iterator是一个典型的工厂模式的例子.那么我们可能会被这两个名词搞晕.首先,我们会奇怪,为什么iterator可以遍历不同类型的结合,其次,出入程序猿的我们根本不知道工厂模式是什么. ...
- VMware Workstation中虚拟机与windows10共享文件夹
设置共享文件夹之前需要确定已经安装VMware Tools 1.在windows桌面新建一个名为share_folder的文件夹用来共享 2.右键点击虚拟机的名字,在弹出的菜单中选择设置 弹出对话框 ...
- JavaScript基础概念与语法
学习了一些最基础的JavaScript语法: <!DOCTYPE html> <html lang="en"> <head> <meta ...