[转]BM 算法中“好后缀”预处理

其实上次在写 BM 算法的原理时,应该把如何实现"好后缀"的预处理一起写上,只是因为急着出去,没有写清楚,只是一带而过,现在把预处理们仔细写一下,希望和对字符串处理技术感兴趣的朋友们探讨。当然,对于 BM 算法还有许多需要思考的,比如证明它的时间复杂度最坏是 O(m)等等问题,并不是一句话就能说明白的。

   

     在上一篇文章中精确字符串匹配(BM算法)提到了 L(i),它是用来存储 t' 最靠右位置 j 的,假设用 t 表示 P[i..n], t' 就是在 P 中重复出现 t 的一段。而 P 也需要向右移,使 L(i) 与 T 中的字符对应。

   如图:

              _____t'     _____t'   _____t

              |   |       |   |     |   |

          a a b c d a q f b c d e e b c d

                              |     |

                             L(i)   i

      

    那么如何在 O(n) 时间计算出 L(i) 呢?

   在这里需要用到一个值 N(j),N(j)是 Zbox (精确字符串匹配(Zbox算法))的相反概念,且 N(j)= Z(n-j+1)。

   如图:

                 j

   Z(j)  a c d b a c d e f

                 |___|

                  Z(j)

   

                 j

   N(j)  a f e m oe m o  

             |___|

              N(j)    

                 

   可见,Z(j) 与 N(j) 一个是和前缀相同的 Zbox 长度,一个是和后缀相同的 Nbox 长度。显然可以根据求 Zbox 的方法求出 Nbox,而求 Zbox 的方法非常简单,而且是 O(n) 的,在Zbox 那篇文章中有详细说明。

   求出了所有的 N(j) 之后,就可以利用它求 L(i) 了。

   算法描述是:

for i:=1 to n do L(i):=0

for j:=1 to n-1 do

    begin

    i := n-N(j)+1;

    L(i) := j;

    end;

   

   以上是预处理中 L(i) 的计算方法。下面写一下预处理中对 l(i)的计算方法。

   l(i) 表示的是最长的 P[i..n] 的后缀的长度,同时这个后缀还要是 P 的前缀,如果不存在,l(i) 就是0。

   如图:

   

     a a c c d e f f a a c

                 i

   图中 l(i)=3。

   结合 N(j),可以看出 l(i)=j, 使 N(j)=j的最大j值,且 j<=|P[i..n]|。

   

来自 <http://blog.chinaunix.net/uid-20338639-id-1964956.html>

   

posted on 2013-08-02 18:34  零风腾飞  阅读(834)  评论(0编辑  收藏  举报

导航