【例题传送门: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. pycharm日常填坑

    pycharm坑很多,今天又遇见了,好吧 ,填坑 场景:从别的地方拷贝过来的项目,导入本地的pycharm 然后选择 然后 还会报错....心累 报错内容: django commands canno ...

  2. 基于 Token 的身份验证:JSON Web Token

    最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,Github 等等,比起传统的身份验证方法,Token 扩展性更强, ...

  3. POJ 2228 Naptime(DP+环形处理)

    题解 这题一眼望去DP. 发现自己太智障了. 这题想的是O(n^3m)的. 环形处理只会断环成链....然后DP也想的不好. 我们先考虑如果除去环这题该怎么做? dp[i][j][0/1]代表到第i小 ...

  4. 拓展Lucas小结

    拓展Lucas是解决大组合数取模非质数(尤其是含平方因子的合数)问题的有力工具... 首先对模数质因数分解,把每个质因子单独拎出来处理答案,然后用中国剩余定理(excrt)合并 问题转化为,对于每个质 ...

  5. 紫书 习题 8-20 UVa 1620 (找规律+求逆序对)

    这道题看了半天没看出什么规律, 然后看到别人的博客, 结论是当n为奇数且逆序数为奇数的时候 无解, 否则有解.但是没有给出证明, 在网上也找到详细的证明--我也不知道是为什么-- 求逆序对有两种方法, ...

  6. WPF Toolkit AutoCompleteBox 实体类绑定 关键字自定义关联搜索匹配

    原文:WPF Toolkit AutoCompleteBox 实体类绑定 关键字自定义关联搜索匹配 WPF Toolkit AutoCompleteBox 实体类绑定 关键字自定义关联搜索匹配 网上的 ...

  7. 嵌入式(C)笔试题

    1 读程序段,回答问题 (a) int main(int argc,char *argv[]) { int c=9,d=0; c=c++%5; d=c; printf("d=%d\n&quo ...

  8. 【hdu 1890】Robotic Sort

    [题目链接]:http://acm.hdu.edu.cn/showproblem.php?pid=1890 [题意] 给你n个数字; i从1到n; 每次让你把第i小的数和数组的第i个元素之间这段区间内 ...

  9. [ACM] hdu 4248 A Famous Stone Collector (DP+组合)

    A Famous Stone Collector Problem Description Mr. B loves to play with colorful stones. There are n c ...

  10. 语法错误: unexpected ''); ?></span></span></h2> ' (T_CONSTANT_ENCAPSED_STRING), expecting ',' or ';'

    语法错误: unexpected ''); ?></span></span></h2>' (T_CONSTANT_ENCAPSED_STRING), expe ...