算法竞赛模板 KMP
KMP算法图解:
①
首先,字符串“BBC ABCDAB ABCDABCDABDE”的第一个字符与搜索词“ABCDABD”的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。
②
因为B与A不匹配,搜索词再往后移。
③
就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。
④
接着比较字符串和搜索词的下一个字符,还是相同。
⑤
直到字符串有一个字符,与搜索词对应的字符不相同为止。
当空格与D不匹配时,你其实知道前面六个字符是“ABCDAB”。KMP算法的想法是,设法利用这个已知信息,不要把“搜索位置”移回已经比较过的位置,继续把它向后移,这样就提高了效率。
⑥
因为空格与C不匹配,搜索词还要继续往后移。
⑦
逐位比较,直到发现C与D不匹配。于是,继续将搜索词向后移动。
⑧
逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。
详解
| 标号(j) | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 模式串(ch) | A | B | C | D | A | B | D |
(1) KMP算法的核心思想
——就是回溯到存在“对称”的地方。
- 注意,这里的“对称”不是指ABCCBA,而是指例如“ABCABC”中队前队尾都分别有1个“ABC”,又例如“ABCCCCCAB”中队前队尾都分别有一个“AB”。
(2) 看图说话
从图中可以分析得出,当扫描到模式串中某一位发现不匹配,总是回溯到在这一位之前的部分模式串存在重复的地方。
- 例如图解⑤中找不到字母“D”(标号3),“D”之前串为“ABCDAB”,存在队前队尾重复“AB”(2个字符),因此退回到队首的“AB”后一位“C”(标号2)。
- 例如图解⑥中找不到字母“C”(标号2),“C”之前串为“AB”,不存在重复的(0个字符),因此退回到队首最前面(标号0)。
所以,next(j)就是当模式串第j位不匹配时即将要退回到的字母标号。
(3) next计算过程
不管第一位和第二位是什么,next(0)=-1,next(1)=0,这是固定的。
ps:模式串“ABCDABD”,下标从0开始哦!
当j=1时,模式串ch[1]=“B”,“B”之前有“A”,不存在重复(0位),所以next[1]=0;
当j=2时,模式串ch[2]=“C”,“C”之前有“AB”,不存在重复(0位),所以next[2]=0;
当j=3时,模式串ch[3]=“D”,“D”之前有“ABC”,不存在重复(0位),所以next[3]=0;
当j=4时,模式串ch[4]=“A”,“A”之前有“ABCD”,不存在重复(0位),所以next[4]=0;
当j=5时,模式串ch[5]=“B”,“B”之前有“ABCDA”,存在重复“A”(1位),所以next[5]=1;
当j=6时,模式串ch[6]=“D”,“D”之前有“ABCDAB”,存在重复“AB”(2位),所以next[6]=2;
(4) nextval对next数组的优化
观察第4位“A”,当它不匹配时,按照next[4]回溯到标号0也为字母“A”,这时再匹配“A”是徒劳的,因为已知“A”不匹配,所以就继续退回到标号0字母“A”的next[0]=-1。为了计算更加直接,就有了nextval对next数组的优化:
只看前面有重复字母的几位就可以。
首先,nextval[0]默认为-1;
当1≤j≤3时,“BCD”在此之前均无重复的字母,所以nextval[j]=next[j];
当j=4时,模式串ch[4]=“A”,next[4]=0,ch[0]=“A”=ch[4],由于“A”=“A”,所以nextval[4]=nextval[0]=-1;
当j=5时,模式串ch[5]=“B”,next[5]=1,ch[1]=“B”=ch[5],由于“B”=“B”,所以nextval[5]=nextval[1]=0;
当j=6时,模式串ch[6]=“D”,next[6]=2,ch[2]=“C”=ch[6],由于“C”≠“D”,所以nextval[6]保持原样,即nextval[6]=next[6]=2;
(5) 代码实现:
功能1:返回模式串ch在主串str中首次出现的位置,未出现输出-1
功能2:返回模式串ch在主串str中出现的次数
#include<bits/stdc++.h>
#define MAX 1000005
using namespace std;
char str[MAX],ch[MAX];
int next[MAX],slen,clen;
void getnext()
{
int i=,j=-;
next[]=-;
while(i<clen)
{
if(j==-||ch[i]==ch[j])
next[++i]=++j;
else j=next[j];
}
}
//返回模式串ch在主串str中首次出现的位置
//返回的位置是从0开始的
int kmp()
{
getnext();
int i=,j=;
while(i<slen&&j<clen)
{
if(j==-||str[i]==ch[j])
{
i++;
j++;
}
else j=next[j];
}
if(j==clen)
return i-clen;
else return -;
} //返回模式串ch在主串s中出现的次数
int Count()
{
int i=,j=,sum=;
if(slen==&&clen==)
{
if(str[]==ch[])
return ;
else return ;
}
getnext();
for(i=;i<slen;i++)
{
while(j>&&str[i]!=ch[j])
j=next[j];
if(str[i]==ch[j])
j++;
if(j==clen)
{
sum++;
j=next[j];
}
}
return sum;
}
int main()
{
while(cin>>str>>ch)
{
slen=strlen(str);
clen=strlen(ch);
cout<<"模式串ch在主串s中首次出现的位置是:"<<kmp()<<endl;
cout<<"模式串ch在主串s中出现的次数:"<<Count()<<endl;
}
return ;
}
算法竞赛模板 KMP的更多相关文章
- 算法竞赛模板 AC自动机
AC自动机基本操作 (1) 在AC自动机中,我们首先将每一个模式串插入到Trie树中去,建立一棵Trie树,然后构建fail指针. (2) fail指针,是穿插在Trie树中各个结点之间的指针,顾名思 ...
- 算法竞赛模板 动态规划之背包DP
① 01背包 有n件物品和一个容量为v的背包.第i件物品的价值是c[i],体积是w[i].求解将哪些物品装入背包可使价值总和最大. 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. ...
- KMP算法(——模板习题与总结)
KMP算法是一种改进的模式匹配算法,相比于朴素的模式匹配算法效率更高.下面讲解KMP算法的基本思想与实现. 先来看一下朴素模式匹配算法的基本思想与实现. 朴素模式匹配算法的基本思想是匹配过程中如果该位 ...
- ACM-ICPC竞赛模板
为了方便打印,不再将代码放到代码编辑器里,祝你好运. ACM-ICPC竞赛模板(1) 1. 几何 4 1.1 注意 4 1.2 几何公式 4 1.3 多边形 6 1.4 多边形切割 9 1.5 浮点函 ...
- Aho-Corasick automaton(AC自动机)解析及其在算法竞赛中的典型应用举例
摘要: 本文主要讲述了AC自动机的基本思想和实现原理,如何构造AC自动机,着重讲解AC自动机在算法竞赛中的一些典型应用. 什么是AC自动机? 如何构造一个AC自动机? AC自动机在算法竞赛中的典型应用 ...
- 算法起步之kmp算法
[作者Idlear 博客:http://blog.csdn.net/idlear/article/details/19555905] 这估计是算法连载文章的最后几篇了,马上就要 ...
- [C++]竞赛模板·数据统计与IO(重定向版与非重定向版)
/* 数据统计与IO 重定向版模板 描述:本机测试用文件数据流重定向,一旦提交到比赛就自动“删除”重定向语句 */ # define LOCAL #include<stdio.h> # ...
- c++算法竞赛常用板子集合(持续更新)
前言 本文主要包含算法竞赛一些常用的板子,码风可能不是太好,还请见谅. 后续会继续补充没有的板子.当然我太菜了有些可能写不出来T^T 稍微有些分类但不多,原谅我QwQ 建议 Ctrl + F 以快速查 ...
- Hihocoder 太阁最新面经算法竞赛18
Hihocoder 太阁最新面经算法竞赛18 source: https://hihocoder.com/contest/hihointerview27/problems 题目1 : Big Plus ...
随机推荐
- springCloud的使用09-----高可用的注册中心
思路:创建多个注册中心,在他们的配置文件中配置相互之间的注册 1 在eureka-server项目的resources目录下创建两个配置文件application-peer1.yml和applicat ...
- [伯努利数] poj 1707 Sum of powers
题目链接: http://poj.org/problem?id=1707 Language: Default Sum of powers Time Limit: 1000MS Memory Lim ...
- putchar(".:-=+*#%@"[(int)(d * 5.0f)])
前两天在玩知乎时候见到有个用C语言画心的小代码感觉还是蛮好玩的,不过,里面有行代码看了好久才懂: putchar(".:-=+*#%@"[(int)(d * 5.0f)]); ,先 ...
- 三、spring的AOP
AOP的基本认识 Aspect Oriented Programming,面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 利用AOP可以对业务逻辑的各个部分进行隔离,从而 ...
- until 循环语句
- /var/lib/dpkg/lock
记性不好: Could not get lock /var/lib/dpkg/lock 锁定的文件会阻止 Linux 系统中某些文件或者数据的访问,这个概念也存在于 Windows 或者其他的操作系统 ...
- Rsync备份服务实战
目录 Rsync备份服务实战 一.Rsync 二.rsync的应用场景 1.Rync的数据同步模式 2.rsync的三种模式 三.rsync配置服务端客户端 四.rsync实战 实战一 报错解决方法: ...
- 【python3】基于scrapyd + scrapydweb 的可视化部署
一.部署组件概览 该部署方式适用于 scrapy项目.scrapy-redis的分布式爬虫项目 需要安装的组件有: 1.scrapyd 服务端 [运行打包后的爬虫代码](所有的爬虫机器都要安 ...
- MariaDB 更新查询
UPDATE 命令通过更改值来修改现有字段. 它使用SET子句指定要修改的列,并指定分配的新值. 这些值可以是字段的表达式或默认值. 设置默认值需要使用DEFAULT关键字. 该命令还可以使用WHER ...
- qt学习(四)主窗选钮,显示新窗口。
游戏有选区这个习惯, 当然,我特指<冒险岛>了,有的时候就是打开一个主屏幕上五个按钮让你点击进入, 甚至有的时候进去了还要选哪个频道,游戏服务器都得分区,频道来完成功能.现在我们先进入想选 ...