后缀数组总结

原文链接:http://www.cnblogs.com/ACAC/archive/2010/05/24/1743090.html

2009-10-25 09:05

后缀数组是处理字符串的有力工具,后缀数组可以解决大多数后缀树解决的问题,由于它的实现要比后缀树简单,因此深受广大ACM爱好者的喜爱,当然还是有一些问题只有后缀树能解决的问题,等学习了后缀树再将其添上。后缀数组最常用的是求取最长公共前缀。

后缀suffix数组,suffix【i】表示从第i个字符开始的后缀;

后缀数组sa,保留1~n的某个排列,保证suffix【sa【i】】<suffix【sa【i】】,可以证明任何从不同位置开始的后缀不可能相等,这里不再证明。

名词数组:名词数组rank【i】保存的是suffix【i】在所有后缀中从小到大排列的名次。简单的说,后缀数组是“排第几的是谁?”,名次数组时“你排第几?”。容易看出,后缀数组和名次数组互为逆运算。

height数组,height【i】表示suffix【sa【i-1】】和suffix【sa【i】】的最长公共前缀,实际中往往应用最多的就是最长公共前缀,用其求取必要的东西。

后缀数组可以解决的问题:

一、单个字符串的问题:

(1)       重复字串  

例1:可重叠最长重复子串

给定一个字符串,求最长重复子串,这两个子串可以重叠。

算法:只要求出最大的height就可以了。

例2:不可重叠最长重复子串(pku 1743)

给定一个字符串,求最长重复子串,这两个子串不能重叠。

算法:二分答案,变成判定性问题,二分代码和判定部分的代码,个人认为最重要的部分:

int le=0,ri=nm-1;

while(le<ri)

{

         int mid=(le+ri+1)/2;

         if(ok(mid,nm)) le=mid;

         else ri=mid-1;

}

最后结果就是le+1;

int ok(int len,int nm)

{

         int i,mx=0,mi=nm;

         for(i=0;i<nm;i++)

         {

                   if(h[i]<len){ mx=0;mi=nm;}

                   else

                   {

                            mx=max(mx,sa[i]);

                            mx=max(mx,sa[i+1]);

                            mi=min(mi,sa[i]);

                            mi=min(mi,sa[i+1]);

                   }

                   if(mx-mi>len) return 1;

         }

         return 0;

}

例2:可重叠的k次最长重复子串(pku 3261)

给定一个字符串,求出至少出现k次的最长重复子串,这k个子串可以重叠。

还是二分判定了。

判定部分的代码:

int appk(int x,int k,int n)

{

         int app=1,i;      

         for(i=0;i<n;i++)

         {

                   if(h[i]>=x)

                   {

                            app++;

                            if(app==k)

                            return 1;

                   }

                   else

                   app=1;

         }

         return 0;

}

转载于:https://www.cnblogs.com/ACAC/archive/2010/05/24/1743090.html

上一篇:【NOI2015】品酒大会【后缀数组】【并查集】


下一篇:Seek the Name, Seek the Fame POJ - 2752