拓展KMP分析
拓展kmp是对KMP算法的扩展,它解决如下问题:
定义母串S,和字串T,设S的长度为n,T的长度为m,求T与S的每一个后缀的最长公共前缀,也就是说,设extend数组,extend[i]表示T与S[i,n-1]的最长公共前缀,要求出所有extend[i](0<=i<n)。
注意到,如果有一个位置extend[i]=m,则表示T在S中出现,而且是在位置i出现,这就是标准的KMP问题,所以说拓展kmp是对KMP算法的扩展,所以一般将它称为扩展KMP算法。
下面举一个例子,S=”aaaabaa”,T=”aaaaa”,首先,计算extend[0]时,需要进行5次匹配,直到发生失配。
从而得知extend[0]=4,下面计算extend[1],在计算extend[1]时,是否还需要像计算extend[0]时从头开始匹配呢?答案是否定的,因为通过计算extend[0]=4,从而可以得出S[0,3]=T[0,3],进一步可以得到 S[1,3]=T[1,3],计算extend[1]时,事实上是从S[1]开始匹配,设辅助数组next[i]表示T[i,m-1]和T的最长公共前缀长度。在这个例子中,next[1]=4,即T[0,3]=T[1,4],进一步得到T[1,3]=T[0,2],所以S[1,3]=T[0,2],所以在计算extend[1]时,通过extend[0]的计算,已经知道S[1,3]=T[0,2],所以前面3个字符已经不需要匹配,直接匹配S[4]和T[3]即可,这时一次就发生失配,所以extend[1]=3。这个例子很有代表性,有兴趣的读者可以继续计算完剩下的extend数组。
1. 拓展kmp算法一般步骤
通过上面的例子,事实上已经体现了拓展kmp算法的思想,下面来描述拓展kmp算法的一般步骤。
首先我们从左到右依次计算extend数组,在某一时刻,设extend[0...k]已经计算完毕,并且之前匹配过程中所达到的最远位置为P,所谓最远位置,严格来说就是i+extend[i]-1的最大值(0<=i<=k),并且设取这个最大值的位置为po,如在上一个例子中,计算extend[1]时,P=3,po=0。
现在要计算extend[k+1],根据extend数组的定义,可以推断出S[po,P]=T[0,P-po],从而得到 S[k+1,P]=T[k-po+1,P-po],令len=next[k-po+1],(回忆下next数组的定义),分两种情况讨论:
第一种情况:k+len<P
如下图所示:
上图中,S[k+1,k+len]=T[0,len-1],然后S[k+len+1]一定不等于T[len],因为如果它们相等,则有S[k+1,k+len+1]=T[k+po+1,k+po+len+1]=T[0,len],那么next[k+po+1]=len+1,这和next数组的定义不符(next[i]表示T[i,m-1]和T的最长公共前缀长度),所以在这种情况下,不用进行任何匹配,就知道extend[k+1]=len。
第二种情况: k+len>=P
如下图:
上图中,S[p+1]之后的字符都是未知的,也就是还未进行过匹配的字符串,所以在这种情况下,就要从S[P+1]和T[P-k+1]开始一一匹配,直到发生失配为止,当匹配完成后,如果得到的extend[k+1]+(k+1)大于P则要更新未知P和po。
至此,拓展kmp算法的过程已经描述完成,细心地读者可能会发现,next数组是如何计算还没有进行说明,事实上,计算next数组的过程和计算extend[i]的过程完全一样,将它看成是以T为母串,T为字串的特殊的拓展kmp算法匹配就可以了,计算过程中的next数组全是已经计算过的,所以按照上述介绍的算法计算next数组即可,这里不再赘述。
2. 时间复杂度分析
下面来分析一下算法的时间复杂度,通过上面的算法介绍可以知道,对于第一种情况,无需做任何匹配即可计算出extend[i],对于第二种情况,都是从未被匹配的位置开始匹配,匹配过的位置不再匹配,也就是说对于母串的每一个位置,都只匹配了一次,所以算法总体时间复杂度是O(n)的,同时为了计算辅助数组next[i]需要先对字串T进行一次拓展kmp算法处理,所以拓展kmp算法的总体复杂度为O(n+m)的。其中n为母串的长度,m为子串的长度。
下面是拓展kmp算法的一道例题。
给你一个字符串ss,然后再给你nn个询问,第ii个询问给你一个数字kk和一个字符串mm
这个询问的答案是tt的最小长度,其中tt是ss的子串,且tt中必须出现kk个mm
Input
第一行一个字符串SS
第二行数字QQ,代表询问次数
后面每一行一个kk和mm,代表依次询问
数据保证所有字母均为小写字母
(1≤|s|≤105)(1≤|s|≤105)
(1≤Q≤105)(1≤Q≤105)
(1≤ki≤|s|)(1≤ki≤|s|)
所有询问长度加起来小于100000100000
保证所有字符串不相同
Output
QQ行,每行代表一个询问的答案
无解请输出−1−1
Sample input and output
Sample Input | Sample Output |
---|---|
aaaaa |
3 |
abbb |
-1 |
代码为:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
int net[maxn],ex[maxn];
char s1[maxn],s2[maxn];
void GETNEXT(char *str)
{
int i=0,j,po,len=strlen(str);
net[0]=len;
while(str[i]==str[i+1]&&i+1<len)
i++;
net[1]=i;
po=1;
for(i=2;i<len;i++)
{
if(net[i-po]+i<net[po]+po)
net[i]=net[i-po];
else
{
j=net[po]+po-i;
if(j<0)j=0;
while(i+j<len&&str[j]==str[j+i])
j++;
net[i]=j;
po=i;
}
}
}
void EXKMP(char *s1,char *s2)
{
int i=0,j,po,len=strlen(s1),l2=strlen(s2);
GETNEXT(s2);
while(s1[i]==s2[i]&&i<l2&&i<len)
i++;
ex[0]=i;
po=0;
for(i=1;i<len;i++)
{
if(net[i-po]+i<ex[po]+po)
ex[i]=net[i-po];
else
{
j=ex[po]+po-i;
if(j<0)j=0;
while(i+j<len&&j<l2&&s1[j+i]==s2[j])
j++;
ex[i]=j;
po=i;
}
}
}
int main()
{
ios::sync_with_stdio(false);//用scanf,printf TLE 。。。
cin.tie(0);
int n,k,len;
cin>>s1;
len=strlen(s1);
cin>>n;
while(n--)
{
cin>>k>>s2;
int len2=strlen(s2),sum=0,temp,cnt=-1;
EXKMP(s1,s2);
for(int i=0;i<len;i++)
{
if(ex[i]==len2)
{
sum++;
if(sum==1) temp=i;
if(sum==k)
{
cnt=i-temp+len2;
break;
}
}
}
cout<<cnt<<endl;
}
return 0;
}
拓展KMP分析的更多相关文章
- HDU 3613 Best Reward(拓展KMP算法求解)
题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. ...
- 拓展KMP算法详解
拓展KMP解决的问题是给两个串S和T,长度分别是n和m,求S的每一个后缀子串与T的最长公共前缀分别是多少,记作extend数组,也就是说extend[i]表示S[i,n-1](i从0开始)和T的最长公 ...
- 拓展kmp总结
借鉴自:https://blog.csdn.net/dyx404514/article/details/41831947 定义母串S,和子串T,设S的长度为n,T的长度为m,求T与S的每一个后缀的最长 ...
- HDU 3613 Best Reward ( 拓展KMP求回文串 || Manacher )
题意 : 给个字符串S,要把S分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串,那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0.问 ...
- HDU 6153 A Secret ( KMP&&DP || 拓展KMP )
题意 : 给出两个字符串,现在需要求一个和sum,考虑第二个字符串的所有后缀,每个后缀对于这个sum的贡献是这个后缀在第一个字符串出现的次数*后缀的长度,最后输出的答案应当是 sum % 1e9+7 ...
- HDU 4300 Clairewd's message ( 拓展KMP )
题意 : 给你一个包含26个小写字母的明文密文转换信息字符串str,第一个表示'a'对应的密文是str[0].'b'对应str[1]……以此类推.接下来一行给你一个另一个字符串,这个字符串由密文+明文 ...
- 拓展KMP求回文串
题目:hdu3613: 题意:有26字母对应的价值,然后给出以个串,把它分成两段字串,如果字串是回文串,串的价值就是每个字符和,不是就为0.求最大价值. 博客 分析:拓展KMP的应用求回文字串. #i ...
- hdu-4300(kmp或者拓展kmp)
题意:乱七八糟说了一大堆,就是先给你一个长度26的字符串,对应了abcd....xyz,这是一个密码表.然后给你一个字符串,这个字符串是不完整的(完整的应该是前半部分是加密的,后半部分是解密了的),然 ...
- hdu-4763(kmp+拓展kmp)
题意:给你一个串,问你满足最大字串既是前后缀,也在字符串除去前后缀的位置中出现过: 思路:我用的是拓展kmp求的前后缀,只用kmp也能解,在字符串2/3的位置后开始遍历,如果用一个maxx保存前2/3 ...
随机推荐
- docker监控容器
Weave Scope: 是能够自动生成一张 Docker 容器web动态图的监控软件,能够让我们直观地理解.监控和控制容器. 监控一台主机: 第一步:安装 [root@localhost ~]# c ...
- 网络编程--UDP通讯
UTP传输 public class Send1 { public static void main(String[] args) throws Exception { Scanner sc=new ...
- 大宇java面试系列(三):Redis常见面试题
1. Redis 是什么?都有哪些使用场景? 我们先来理解经典的CAP理论: 一致性:是指从数据层面来看的一致性. 可用性:是指从系统层面的可用性. 容错性:是指从网络层面的的容错性. 数据库逐渐从关 ...
- .NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
.NET Core love gRPC 千呼万唤的 .NET Core 3.0 终于在 9 月份正式发布,在它的众多新特性中,除了性能得到了大大提高,比较受关注的应该是 ASP.NET Core 3. ...
- mac软件推荐及chrome插件推荐
通用软件 Alfred (超级好用的效率工具) 用mac这个软件一定要装,用习惯之后加上电脑本身的快捷键.效率提升的飞起. Alfred我常使用的功能有: 搜索chrome的书签 我搜索的书签大概分为 ...
- 20191010-4 alpha week 1/2 Scrum立会报告+燃尽图 02
此作业要求参见https://edu.cnblogs.com/campus/nenu/2019fall/homework/8747 一.小组情况 组长:迟俊文 组员:宋晓丽 梁梦瑶 韩昊 刘信鹏 队名 ...
- 【2018寒假集训Day 8】【最小生成树】Prim和Kruskal算法模板
Luogu最小生成树模板题 Prim 原理与dijkstra几乎相同,每次找最优的点,用这个点去松弛未连接的点,也就是用这个点去与未连接的点连接. #include<cstdio> #in ...
- 【Luogu P2563】【集训Day 4 动态规划】质数和分解
题目链接:Luogu P2563 质数和分解(prime) [问题描述] 任何大于 1 的自然数 N,都可以写成若干个大于等于2且小于等于 N 的质数之和表达式(包括只有一个数构成的和表达式的情况), ...
- Anaconda中启动Python时的错误:UnicodeDecodeError: 'gbk' codec can't decode byte 0xaf in position 553
今天,在Anaconda prompt启动python遇到了如下错误: UnicodeDecodeError: ‘gbk’ codec can’t decode byte 0xaf in positi ...
- Mysql数据库调优和性能优化的21条最佳实践
Mysql数据库调优和性能优化的21条最佳实践 1. 简介 在Web应用程序体系架构中,数据持久层(通常是一个关系数据库)是关键的核心部分,它对系统的性能有非常重要的影响.MySQL是目前使用最多的开 ...