扩展kmp

字符串 扩展kmp

1.1 引例

扩展kmp,求解如下问题:

问s串与t串的每一个后缀的最长公共前缀

容易发现:当某一个最长公共前缀等于s串的长度的时候,其实就是一个s串与t串的kmp匹配问题,因此得名“扩展”kmp。事实上,扩展kmp与普通kmp有一定的区别,两者并不是完全是拓扑关系。即使完全没学过kmp,直接上手学扩展kmp也不是天方夜谭

2.1 强化条件:当s与t完全相同时

先尝试通过强化条件,降低一下难度:假如s与t完全相同,扩展kmp该如何实现?

当s与t完全相同,其实问题可以进一步转化为“s与s的每一个后缀的最长公共前缀”。为了方便记录,规定:(nxt[i])表示 s[1..n]与s[i..n]的最长公共前缀长度。

从最浅显易懂的地方入手。nxt[1]=s串长度,这一点我们从定义便可知;nxt[2]则暴力地枚举一遍,(O(n))解决

上述部分的代码

nxt[1]=lenb;
int now=0;
while(now+2<=lenb&&b[now+1]==b[now+2]) now++;
nxt[2]=now;

考虑如何转移,扩展kmp是一个线性算法,因此当我们求解nxt[k]时,nxt[i]((1leq i < i))已经得到了求解。我们设i+nxt[i]-1的最大值为p,此时的i坐标为p0

e7Fm5t.png

记K在nxt[p0]中对应的位置,具体而言k-p0+1,=a,另L=nxt[a]

e7k9ds.png

当a+l-1< P时

e7ky6S.png

根据nxt[p0]和nxt[a]的定义,得知所有的绿色区域都是相同的。nxt[p0]的定义可知,两个红色框相同;而nxt[a]的定义可知,蓝框与红框不相同,因此无法继续匹配下去。此时:nxt[k]=nxt[a]

当a+1-l>= P时

e7VJyT.png

此时由于超出了P的范围,对于P以后的区间的信息是一无所知的,因此此时只有nxt[k](geq)P-k+1 之后我们需要暴力地枚举下去,直到失配

代码如下:

lor(i,3,lenb){
    if(i-1+nxt[i-p+1]<p+nxt[p]-1) nxt[i]=nxt[i-p+1]; // 情况一
    else{                                            // 情况二
        int now=max(0,p+nxt[p]-i);  //这是为了防止P小于k的情况
        while(i+now<=lenb&&b[1+now]==b[i+now]) now++;
        nxt[i]=now; p=i;  // 暴力枚举后,更新答案
    }
}

至此,我们得到了强化条件版:s对于s的所有后缀的最长公共前缀求解

3.1 回归原条件:当s与t不等的时候

为了区分,我们将这种情况下的匹配记录为extend[i],extend[i]表示s与t[i..n]的最长公共前缀的长度

其实,当我们分析完nxt[]数组的求解之后,会发现原问题已经在无形中被解决了

暴力地预处理extend[1]:

int now=0;
while(1+now<=lena&&1+now<=lenb&&a[1+now]==b[1+now]) now++;
extend[1]=now; p=1;

模仿nxt[]去分类讨论,只是这时候上方s[]的坐标p的含义变更为:p0+extend[p0]-1的最大值

e7ZIUJ.png

e7ZxVe.png

两种分类讨论其实无非就是把原先的两个nxt数组的利用,改为T[]的extend和s[]的nxt。代码部分也是略微修改即可。为了避免累赘本人太懒直接上代码

lor(i,2,lena){
    if(i-1+nxt[i-p+1]<p+extend[p]-1) extend[i]=nxt[i-p+1];  // 情况一
    else{                                                   // 情况二
        int now=max(0,p+extend[p]-i);
        while(1+now<=lenb&&i+now<=lena&&b[1+now]==a[i+now]) now++;
        extend[i]=now; p=i;
    }
}

4.1 总结

虽然后缀数组可以取代扩展kmp,但是如同树状数组和线段树的关系,扩展kmp有着常数小,容易写(虽然我觉得后缀数组更好写)的优点。

此外经过实测(10^6)级随机数据,发现速度从快到慢为:mp> kmp> ex_kmp ...

这..可能就是强大的代价吧 ( _ _)ノ|

原文链接: https://www.cnblogs.com/ticmis/p/13211149.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    扩展kmp

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/360344

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午1:13
下一篇 2023年3月2日 下午1:14

相关推荐