zoukankan      html  css  js  c++  java
  • 扩展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!!!!!

    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    SpringBoot使用Swagger2实现Restful API
    SpringBoot返回json和xml
    SpringBoot定时任务
    SpringBoot+Jpa+MySql学习
    SpringBoot+Mybatis+MySql学习
    linux安装jdk
    linux下安装mysql
    利用nginx,腾讯云免费证书制作https
    SpringBoot使用数据库
    SpringBoot的国际化使用
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6286181.html
Copyright © 2011-2022 走看看