KMP能计算一个字符串的每个位置前最长公共前缀后缀

扩展KMP可以用来计算两个字符串间的最长公共前缀后缀的……

不过为了计算这个需要绕些弯路

已知字符串$S$和$P$,$S$的长度为$n$,$P$的长度为$m$

扩展KMP实际是计算$E$数组,设$E[i]$为字符串$S[i..n-1]$与字符串$P$的最大公共前缀

尝试数学归纳法

$E[0]$显然只能直接依次比对,因为什么信息都没有

假设$E[0]\sim E[i-1]$都计算出来了,现在计算$E[i]$

不妨= =,利用$E[i-1]$的信息,第二行的矩形的宽度表示$E[i-1]$,只有这个信息是不够的,否则计算$E[i]$还是需要重复跑计算$E[i-1]$跑过的距离

假设有“$P[i..m-1]$与$P$的最大公共前缀长度”的信息,设为$N[i]$

  • 如果$i\geqslant (i-1)+E[i-1]$,说明上个信息对这个没帮助,直接往右跑
  • 如果$i+N[1]\geqslant (i-1)+E[i-1]$,由于红线右边的P与S是否相等不确定,因此要舍去红线右边的部分,那么经过如图的变形(第三排和第四排的矩形),可以直接从上一次失败的地方继续(红线处)
  • 如果$i+N[1]<(i-1)+E[i-1]$,因为在红线前就失败了,那么直接就可以得到$E[i]=N[1]$

由于第一种情况中仍然可能重复对比$S$和$P$,$E[i-1]$可能不是最好的选择,那么我们就选红线最靠右的$E[k]$来计算$E[i]$

  • 如果$i\geqslant j$,说明上个信息对这个没帮助,直接往右跑
  • 如果$i+N[i-k]\geqslant j$,由于红线右边的P与S是否相等不确定,因此要舍去红线右边的部分,那么经过如图的变形(第三排和第四排的矩形),可以直接从上一次失败的地方继续(红线处)
  • 如果$i+N[i-k]< j$,因为在红线前就失败了,那么直接就可以得到$E[i]=N[i]$

这样,在知道$N[i]$的情况下,可以$\mathcal{O}(n)$得到$E$数组(因为S与P的比较不会重复),前两种情况可以合并为一个,并且可以省去单独计算$E[0]$

代码:

inline void getE() {
int k = 0, j=0;
REP(i,0,n) {
if( i>=j || i+N[i-k] >= j ) {
if( i>=j ) j=i;
while( j < n && j - i < m && s[j] == p[j-i]) j++;
E[i] = j-i;
k = i;
} else {
E[i] = N[i-k];
}
}
}

对于$N$数组,和求$E$数组类似

$N[0]=m$,$N[1]$直接计算,假设$N[0]\sim N[i-1]$都求出来了,选红线最靠右的$N[k]$,那么

  • 如果$i\geqslant j$,说明上个信息对这个没帮助,直接往右跑
  • 如果$i+N[i-k]\geqslant j$,那么直接从上一次失败的地方继续(红线处)
  • 如果$i+N[i-k]< j$,因为在红线前就失败了,那么$N[i]=N[i-k]$

代码:

inline void getN() {
int k = 0, j=0;
N[0] = m;
REP(i,1,m) {
if( i>=j || i+N[i-k] >= j ) {
if( i>=j ) j=i;
while( j < m && p[j] == p[j-i]) j++;
N[i] = j-i;
k = i;
} else {
N[i] = N[i-k];
}
}
}

HDU-2594

题目

给两个字符串,第一个字符串与第二个字符串的最长公共前缀后缀

题解

直接套用EXKMP第一个字符串设为p,第二个字符串设为s,找到第一个i,使E[i]=n-i,就可以了

AC代码

#include<cstdio>
#include<cstring>
#include<cassert>
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__),fflush(stdout)
#else
#define DBG(...) (void)0
#endif // sahdsg
using namespace std;
#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define MAXN 50007
char p[MAXN], s[MAXN];
int N[MAXN], m;
int E[MAXN], n; inline void getN() {
int k = 0, j=0;
N[0] = m;
REP(i,1,m) {
if( i>=j || i+N[i-k] >= j ) {
if( i>=j ) j=i;
while( j < m && p[j] == p[j-i]) j++;
N[i] = j-i;
k = i;
} else {
N[i] = N[i-k];
}
}
} inline void getE() {
int k = 0, j=0;
REP(i,0,n) {
if( i>=j || i+N[i-k] >= j ) {
if( i>=j ) j=i;
while( j < n && j - i < m && s[j] == p[j-i]) j++;
E[i] = j-i;
k = i;
} else {
E[i] = N[i-k];
}
}
} int main() {
#ifdef sahdsg
freopen("in.txt", "r", stdin);
#endif // sahdsg
while(~scanf("%s%s", p,s)) {
n=strlen(s),m=strlen(p);
getN();
getE();
int t=-1;
// REP(i,0,n) DBG("%d ", E[i]);
REP(i,0,n) {
if(E[i]==n-i) {
t=i;
break;
}
}
if(~t) {
printf("%s %d\n", s+t, n-t);
} else puts("0");
} return 0;
}

扩展KMP笔记的更多相关文章

  1. HDU 4333 Revolving Digits [扩展KMP]【学习笔记】

    题意:给一个数字,每一次把它的最后一位拿到最前面,一直那样下去,分别求形成的数字小于,等于和大于原来数的个数. SAM乱搞失败 当然要先变SS了 然后考虑每个后缀前长为n个字符,把它跟S比较就行了 如 ...

  2. 扩展kmp学习笔记

    kmp没写过,扩展kmp没学过可还行. 两个愿望,一次满足 (该博客仅用于防止自己忘记,不保证初学者能看懂我在瞎bb什么qwq) 用途 对于串\(s1,s2\),可以求出\(s2\)与\(s1\)的每 ...

  3. 扩展KMP算法

    一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...

  4. 扩展KMP --- HDU 3613 Best Reward

    Best Reward Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权 ...

  5. KMP和扩展KMP

    文章网上太多这里提一下代码细节: KMP: scanf("%s\n",s); scanf("%s\n",t); int ls=strlen(s),lt=strl ...

  6. UVA5876 Writings on the Wall 扩展KMP

    扩展KMP的简单题. #include<stdio.h> #include<string.h> #define maxn 51010 char s[maxn],t[maxn]; ...

  7. hdu4333 扩展KMP

    慢慢研究可以发现,可以用扩展kmp来求.由于扩展kmp的next[]只有一部分,当前位子前面那部分和母串的后部分,所以可以将字符串复制接在后面一次. 先求如果next[]>0&& ...

  8. 扩展KMP

    刘雅琼论文 http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 论文讲的非常详细. 给定母串S,子串T,n=strlen(S),m=st ...

  9. HDU 3336 扩展kmp

    题目大意: 找到字符串中所有和前缀字符串相同的子串的个数 对于这种前缀的问题,通常通过扩展kmp来解决 其实吧这是我第一次做扩展kmp的题目,原来确实看过这个概念,今天突然做到,所以这个扩展kmp的模 ...

随机推荐

  1. Flask request和response

        Response # -*- coding: utf-8 -*-   from flask import Flask, redirect, render_template, jsonify,  ...

  2. 性能调优 -- TPS&QPS

    无论在工作中,还是看一些技术文章的时候,经常听到TPS.QPS这两个术语,那么两者分别是什么?又有哪些区别? QPS:query per second,是指单位时间内请求的数量. TPS:表示一个事务 ...

  3. MyBatis映射文件 相关操作

    一.MyBatis映射文件 1.简介 MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行 ...

  4. VUE,基于vue-cli搭建创建vue项目

    前提:必须安装node.js,官方地址:https://nodejs.org/en/ 然后安装vue-cli 安装方式:cmd命令行安装:打开cmd命令符输入进行全局安装脚手架:npm install ...

  5. [转]自定义UiPath Activity实践

    本文转自:https://segmentfault.com/a/1190000017440647 为了对UiPath Activity的实现方式一探究竟,自己尝试实践编写了一个简单的Activity, ...

  6. IDEA新建Spring配置文件的方法

    IDEA创建Spring Config 选择项目文件右键 输入文件名称即可 applicationContext.xml

  7. 如何在Oracle 12C中添加多个分区 (Doc ID 1482456.1)

    How to Add Multiple Partitions in Oracle 12C (Doc ID 1482456.1) APPLIES TO: Oracle Database - Enterp ...

  8. RTP中的H264的SVC相关信息

    概览 本文简单的介绍了rtp中的h264的svc相关信息 h264的svc相关格式信息 从RTP Payload Format for H.264 Video可以看见264在rtp的传输过程中,在rt ...

  9. 你必须知道的Dockerfile

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 一.关于Dockerfile 在Docker中创建镜像最常用的方式,就是使用D ...

  10. 你真的会用搜索吗?—— google 搜索技巧

    鄙人用了那么多年 google ,却只会简单的空格. 虽然空格已经很强大了.google 对此做了非常多的优化,原则是让你只用最基础的输入搭配空格就能达到跟下面介绍的方法几乎一样的效果,但是还有知道一 ...