扩展kmp——原创

扩展kmp                 LRH

所谓扩展kmp指的是与kmp相似的求辅助数组的原理,但是本身与kmp关系不大。

1.exkmp的用途:给定一个主串s和一个子串t,求出s中每一个后缀和子串t的最长公共前缀。

2.算法推导:

给定一个主串:S=aaaaaaaaaabaaa

 T=aaaaaaaaaaa

(下标都是从零开始!!!)

                 第一步

需要有两个辅助数组:extand[i]和next[i];

extand[i]:表示主串S以i开始的后缀与子串T的最长公共前缀。

next[i]:表示子串T中以i开始的后缀与子串本身的最长公共前缀。

首先看这个样例,很显然extend[1]=10。然后要求extend[2]。如果暴力求的话还要再用每个字符比较一遍太过麻烦。那么已经求得的extend[1]是不是可以利用呢?

通过求得的extend[1]我们已经知道了:S[1...10]=T[1…10](不知道为什么的看定义去)。那么S[2..10]=T[2…10]。再算extend[2]时很明显extand[1]是没有用的,所以要从S[2]匹配。于是我们就要再引入一个数组next[i]。根据定义:

因为next[2]=9;

所以T[211]=T[110]

所以T[210]=T[19](都删去一个字符)

所以T[19]=S[210]

所以extand[2]就等于9啊!!!多么神奇啊!

第二步

求完extand[2]后就可以知道这种求法原理是一种递推的。那么下面我们抛开特殊来看一般

我们假设extand[1…k]已经求好(就像刚刚那个extand[1]已经求好一样)。并且,在以前匹配过程中在S当中所匹配到的最远位置是p那么这个最远的位置是不是就是i+extand[i]-1?(当前位置+匹配长度-1=匹配到的末端位置),其中i=1…k。不妨取这个最远的位置所对应的i是a很显然这个a是比p要小的。那么根据定义就可以推出           S[ap]=T[1p-a+1];

所以 S[k+1p]=T[k+a+2p-a+1](都删去一段字符)

我们再定义一个L,另L= extand[k-a+2](注意:这是定义的,不要老是纠结他究竟是为了什么,不然会很痛苦!!!这个会用到的。)

那么根据L就可以推导出:T[1L]=T[k-a+2k+L-a+1]

相信看到这里大多数人都已经懵逼了,那我们还是先回想一下next数组的定义,然后画个图就能懂了:

是不是已经懂了?这是next数组的一个性质,前面在推extand[2]的时候应经用了。

第三步

现在就出现了两种情况:

(一) k+L<p

图中红色的区域一定是相等的,即S[k+1k+1+L]=T[1L]

因为前面已经推导过T[1L]=T[k-a+2k+L-a+1](1)

并且S[k+1p]=T[k+a+2p-a+1](2)   p>k+L

所以(1)式的右端点在(2)式右端点的左边。

所以 多出来的那块=(p-a+1)-(k+L-a+1)

再用p-[(p-a+1)-(k+L-a+1)]+1=k+L+1!

所以就推出了S[k+1k+L+1]=T[1L]

那么就可以知道蓝色的部分一定不会相等(因为L=extend[k-a+2]呀,如果相等的话那extend[k-a+2]不就等于L+1甚至更大了吗?)

为什么k+L不能=p?  因为小于p时p之前一定存在一个字符与T[L+1]不匹配(图中蓝色区域)。如果等于p,那就无法判断下一位是否不匹配了。

所以我们就得出了extend[k+1]=L,就求出来了!

(二) k+L>=p

明白了第一种,这种情况就比较通俗易懂啦!

上图的紫色部分是未知的,红色部分是已经匹配的。因为在计算extend[1…k]时达到的最远位置是p,所以p之后的的位置无法访问。那怎么办?问我??这还用说:暴力求啊!

从S[p+1]和T[p-k+1]开始匹配不就完啦?之后更新extend[a]+a和extend[k+1]+k+1的大小,后者的就更新最远位置p然后,,,就没有然后了!!!!

那么next数组怎么求呢?其实next数组就是一个以T为主串,T为字串的一个特殊的扩展kmp!用上文介绍的相同算法计算next数组即可。

唉!这就完了。写了整整一个晚上,因为下午刚学,连推公式带迷茫的痛苦了三个小时,终于完成了再附一个代码:

Return 0!!!!!

时间: 2024-10-08 20:04:26

扩展kmp——原创的相关文章

浅谈Manacher算法与扩展KMP之间的联系

首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解,网上解法颇多,时间复杂度也不尽相同,这里列述几种常见的解法. 解法一 通过枚举S的子串,然后判断该子串是否为回文,由于S的子串个数大约为,加上每次判断需要的时间,所以总的时间复杂度为,空间复杂度为. bool check(string &S, int left, int right) { while (left < right && S[left]

hdu4333 Revolving Digits(扩展kmp+kmp最小循环节)

题目链接:点击打开链接 题意描述:给定一个字符串,可以把字符串的后x位移到字符串前面组成一个新的字符串?问对于所有的新组成的字符串中去掉重复的之后,比原串小的个数,等于的个数,大于的个数? 解题思路:扩展KMP(next1[i]数组含义:x[i···len-1]与x[0···len-1]的最长公共前缀) 分析:首先我们把字符串s复制一遍接到原字符串后面形成ss,这样在ss中以i(i>=0&&i<len)为起点的长度为len的字符串就是所有可能的新字符串: 讲到这里,问题转变为在

hdu2328 Corporate Identity 扩展KMP

Beside other services, ACM helps companies to clearly state their "corporate identity", which includes company logo but also other signs, like trademarks. One of such companies is Internet Building Masters (IBM), which has recently asked ACM for

扩展KMP算法

扩展KMP,用于求s的后缀的最长前缀.用extand数组表示第i个后缀的最长前缀的字符个数. 注意几点:1.next数组是对T的   2.extand数组是对S的 3.应用:回文,重复串等 代码如下: 1 #include<iostream> 2 #include<string> 3 #include<cstdio> 4 using namespace std; 5 const int MM=100005; //长度最大值 6 int next[MM],extand[M

扩展KMP模板

扩展KMP:    给出模板串A和子串B,长度分别为lenA和lenB,要求在线性时间内,对于每个A[i](0 <= i < lenA),求出A[i..lenA-1]与B的最长公共前缀长度,记为ex[i](或者说,ex[i]为满足A[i..i + z - 1]==B[0 .. z - 1]的最大的z值).    扩展KMP可以用来解决很多字符串问题,如求一个字符串的最长回文子串和最长重复子串.[算法]    设next[i]为满足B[i..i + z - 1] == B[0..z - 1]的最

扩展KMP - HDU 4333 Revolving Digits

Revolving Digits Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=4333 Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. analyse: KMP的经典题. 首先我们将原串扩展成两倍,算一遍扩展KMP(自匹配),时间复杂度O(n). 这样一来,我们就得到了eKMP[i],eKMP[i]代表s[i...len-1]与s的最长

HDU 4300 (扩展KMP或KMP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 题意:说实话,看半天题目,愣是没看懂,百度题意才看懂,大概意思就是:第一个串串为匹配串,第i个代表字母顺序中的第i个,比如第一个是q,那么,q就代表a. 第二个串是密文+明文,密文全部都有,但明文可能不全,输出完整的密文+明文. 题解:有两种做法,第一种,用扩展KMP: 1.先把s2砍半,前面一半必定为密文,后面一半可能是密文+明文. 2.把前面的一半转化成明文. 3.用后面的和前面的找最长公

Part.5【马拉车&amp;扩展KMP】

Manacher(马拉车)是一种求最长回文串的线性算法,复杂度O(n).网上对其介绍的资料已经挺多了的,请善用搜索引擎. 而扩展KMP说白了就是是求模式串和主串的每一个后缀的最长公共前缀[KMP更像是一个自动机] 题目: POJ 1159: Palindrome 求原字符串最少增加几个字符后可变成回文串,相当于求最长回文子序列的长度. 解法:直接求串S和反转串Sr的最长公共子序列. #include <cstdlib> #include <cstdio> #include <

KMP与扩展KMP

原文转自:http://www.cppblog.com/MatoNo1/archive/2011/04/17/144390.aspx KMP:给出两个字符串A(称为模板串)和B(称为子串),长度分别为lenA和lenB,要求在线性时间内,对于每个A[i] (0<=i<lenA),求出A[i]往前和B的前缀匹配的最大匹配长度,记为ex[i](或者说,ex[i]为满足A[i- z+1..i]==B[0..z-1]的最大的z值).KMP的主要目的是求B是不是A的子串,以及若是,B在A中所有出现的位置