【例题传送门:caioj1177


KMP模版:子串是否出现

【题意】
有两个字符串SA和SB,SA是母串,SB是子串,问子串SB是否在母串SA中出现过。
如果出现过输出第一次出现的起始位置和结束位置,否则输出"NO"
【输入文件】
第一行SA(1<= 长度<=1000000)
第二行SB(1<= 长度<=1000)
【输出文件】
如果SB在SA中出现过输出第一次出现的起始位置和结束位置,否则输出"NO"
【样例1输入】
aaaaabaa
aab
【样例1输出】
4 6
【样例2输入】
aaaaabaa
aax
【样例2输出】
NO


算法分析:

  KMP其实就是一种偷懒的方式,通过访问前面已经遍历过的位置来首先给定一个可继承的值,然后暴力(汗......)

  首先定义一个p数组,p[i]=j时,代表SA字符串[1...j]与SA字符串[i-j+1...i]所形成的子串完全相同

  那么我们怎么得出这个p数组呢?

  就是暴力+偷懒!!!(其实前面已经讲了,尴尬)

  当我们访问到i这个点时,我们先访问一下i-1,因为我们访问到i的时候已经把1~i-1的p数组求出来了,那么请看下面的图:

  我们设j=p[i-1],i-1-j+1=i-j,那么我们可以知道SA[1...j]=SA[i-j...i-1],也就是上图的红色区间,那假如SA[j+1]=SA[i]的话,我们就可以直接p[i]=j+1对吧

  但是现实是残酷的(AC没有那么容易~),那么当SA[j+1]!=SA[i]的时候怎么办呢?那么我们就找p[j]!!!如图:

  我们再设一个变量k=p[j],因为p[j]的定义,所以我们可以得到SA[1...k]=SA[j-k+1...j],也就是前两个棕色区间,这时因为两个红色区间相同,所以我们可以得到SA[1...k]=SA[i-j...i-j+k-1],也就是第一个和第三个棕色区间相等,接着又可以得到SA[j-k+1...j]=SA[i-k(i-1-k+1)...i-1],也就是第二个和第四个的棕色区间相等,然后!!!我们得到四个棕色区间相等!!!我们就可以判断SA[k+1]和SA[i]是否相等来求p[i],如果相等,p[i]=k+1,否则继续找p[k]。一直找啊找,直到找到没得找也就是当前的p[p[p[p[p[p[.......的值为0时,那么我们就判断SA[1]和SA[i]是否相同,相同p[i]=1,否则p[i]=0

  其实也不算暴力,而是利用p数组的定义来寻找前面可以用来继承的点!!

  但是到了这里,还没有完成KMP的学习

  我们的p数组只对SA字符串,也就是题目中的子串进行了处理

  那么p数组对于我们求答案有什么帮助呢?

  

  我们设j为SB字符串中的i-1位置开始所组成的后缀,与SA字符串中的1位置开始的前缀的最长公共长度,也就是SA[1...j]=SB[i-j(i-1-j+1)...j-1],那么我们可以判断SA[j+1]和SB[i]是否相等,相等就记录j的值,不相等就找p[j]!!!是不是似曾相识的步骤,没错!就是把SB中的i转移到SA中进行求解,这样就是KMP的全部了!


参考代码:

#include<cstdio>
#include<cstring>
using namespace std;
char sa[],sb[];//sa是母串,sb是子串
int p[];//p数组是为子串准备的,p的含义和母串一点关系都没有。
//p[i]表示sb中 以第i个字符为结尾,往前最多拉多少个字符(sb[i]结尾的后缀)可以完全匹配sb的前缀
//比如 sb="abcdabc"中 p[7]=3, 就这样,我当你理解p[i]的含义了
int main()
{
int lena,lenb,i,j;
scanf("%s",sa+);lena=strlen(sa+);
scanf("%s",sb+);lenb=strlen(sb+);
//制造P数组
p[]=;
for(i=;i<=lenb;i++)
{
j=p[i-];//先记录p[i-1]
while(j>&&sb[i]!=sb[j+]) j=p[j];
/*
这里有两种情况
如果j+1的位置的字符等于i位置的字符的话,那就直接把p[i]=j+1
否则就找j的p值,因为1~sb[p[j]]一定是1~sb[j]的后缀
*/
if(sb[i]==sb[j+]) p[i]=j+;else p[i]=;
}
int st,ed;
j=;
for(i=;i<=lena;i++)//紧接着用p数组来匹配母串
{
while(j>&&sa[i]!=sb[j+]) j=p[j];
if(sa[i]==sb[j+]) j++;
if(j==lenb){ed=i;st=i-lenb+;break;}//得到答案后就记录开头与结尾
}
if(j==lenb) printf("%d %d\n",st,ed);
else printf("NO\n");
return ;
}

算法导论————KMP的更多相关文章

  1. 经典算法系列--kmp

    前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k:但是问题在于如何求出这个最大前后缀长度呢?我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破,后来翻看算法导 ...

  2. 【转】【经典算法】——KMP,深入讲解next数组的求解

    前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k:但是问题在于如何求出这个最大前后缀长度呢?我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破,后来翻看算法导 ...

  3. "《算法导论》之‘字符串’":字符串匹配

    本文主要叙述用于字符串匹配的KMP算法. 阮一峰的博文“字符串匹配的KMP算法"将该算法讲述得非常形象,可参考之. 字符串‘部分匹配值’计算 KMP算法重要的一步在于部分匹配值的计算.模仿& ...

  4. B树——算法导论(25)

    B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...

  5. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  6. 基本数据结构(2)——算法导论(12)

    1. 引言     这一篇博文主要介绍链表(linked list),指针和对象的实现,以及有根树的表示. 2. 链表(linked list) (1) 链表介绍      我们在上一篇中提过,栈与队 ...

  7. 堆排序与优先队列——算法导论(7)

    1. 预备知识 (1) 基本概念     如图,(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树.树中的每一个结点对应数组中的一个元素.除了最底层外,该树是完全充满的,而且从左向右填充.堆的数组 ...

  8. quickSort算法导论版实现

    本文主要实践一下算法导论上的快排算法,活动活动. 伪代码图来源于 http://www.cnblogs.com/dongkuo/p/4827281.html // imp the quicksort ...

  9. 算法:KMP算法

    算法:KMP排序 算法分析 KMP算法是一种快速的模式匹配算法.KMP是三位大师:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,所以取首字母组成KMP. 少部分图片来自孤~影 ...

随机推荐

  1. 垃圾回收器(GC)

    值类型占用的空间在方法执行结束后会被马上释放, 引用类型占用的空间在方法结束后不会被马上释放,具体什么时间释放由垃圾回收器(GC)来决定. GC(Garbage Collection):JAVA/.N ...

  2. django orm 基本

    1 modle基本数据类型 class Test(models.Model): """测试学习用""" Auto = models.Auto ...

  3. Generator 简介

    Generator 就是一种状态机,封装多个内部状态. 执行 Generator 函数会返回一个遍历器对象(),也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数.返回的遍历器对 ...

  4. CodeForces 453A

    Twilight Sparkle was playing Ludo with her friends Rainbow Dash, Apple Jack and Flutter Shy. But she ...

  5. Step by Step Do IOS Swift CoreData Simple Demo

    简单介绍 这篇文章记录了在 IOS 中使用 Swift 操作 CoreData 的一些基础性内容,因为缺乏文档,基本上都是自行实验的结果.错漏不可避免,还请谅解. 部分内容借鉴了 Tim Roadle ...

  6. 关于MAVEN找不到JDK的那点事

    自从SUN被Oracle收购以后.JDK就由Oracle来提供了. 在新版本号之中,假设你下载安装JDK以后,又选择了JRE安装(当然,如今JRE直接叫做Java了),那么,恭喜你,在 C:\wind ...

  7. jsp中对话框的实现

    <Input type=submit name="g" style="font-size:20px" value="提交" oncli ...

  8. 1264: [AHOI2006]基因匹配Match(动态规划神题)

    1264: [AHOI2006]基因匹配Match 题目:传送门 简要题意: 给出两个序列.每个序列都由n种不同的数字组成,保证每个序列种每种数字都会出现5次(位置不一定一样),也就是序列长度为5*n ...

  9. 基于python3-sklearn,Flask 的回归预测系统

    看到一副图片挺有意思,放在片头 序 "傍晚小街路面上沁出微雨后的湿润,和煦的西风吹来,抬头看看天边的晚霞,嗯明天又是一个好天气.走到水果摊旁,挑了个根蒂蜷缩.敲起来声音浊响的青绿西瓜,一边满 ...

  10. Android 如何打造Android自定义的下拉列表框控件

    一.概述 Android中的有个原生的下拉列表控件Spinner,但是这个控件有时候不符合我们自己的要求, 比如有时候我们需要类似windows 或者web网页中常见的那种下拉列表控件,类似下图这样的 ...