后缀数组学习&模板
学习链接:
http://blog.csdn.net/whyorwhnt/article/details/32933319 ,里面说的很清楚,各个变量的解释还蛮清晰
该链接里面有很多文章,这篇有图形解释,容易理解: http://www.cppblog.com/superKiki/archive/2010/05/15/115421.html 不过有书看也更好
后缀数组的思想:
先比较所有后缀的 前2^0次方个字符,然后比较 前2^1次方个字符,然后 2^2,2^3,... 直到所有后缀的 前2^i 个字符比较不存在完全相同的情况,就停止。
1. 基数排序,用来减少排序复杂度
学习链接:http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html
2. 循环得出答案
3. 注意终止条件
4. 有的时候da(int *r) ; valheight(int *r),你可能要改为 char*r; 一般对最后一位r[n]=0赋值,最好是用任何一个小于你会用到的字符串集的字符,比如对于(A-Z)-(a-z)你就可以 r[n]='$';
5. 单纯的da是没法用的,一般我们都会用rank[]和height[],链接里也有,height保存的是LCP,即最长公共前缀。
6. RMQ,查询,查询 i位置 开始的后缀和 j位置 开始的后缀的LCP,为了减少复杂度,我们要用到简便算法,a) 线段树; b) ST算法。后者用得比较多。
RMQ学习链接:http://kmplayer.iteye.com/blog/575725
倍增算法模板:
(注意 n 还是 n+1 ;从 1 开始 还是 从 0 开始)
const int N = int(2e5)+10;
int cmp(int *r,int a,int b,int l){
return (r[a]==r[b]) && (r[a+l]==r[b+l]);
}
// 用于比较第一关键字与第二关键字,
// 比较特殊的地方是,预处理的时候,r[n]=0(小于前面出现过的字符)
int wa[N],wb[N],ws[N],wv[N];
int rank[N],height[N];
void DA(int *r,int *sa,int n,int m){ //此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i
=0;i--) sa[--ws[x[i]]]=i; //预处理长度为1
for(j=1,p=1;p
=j) y[p++]=sa[i]-j; //利用长度J的,按第二关键字排序
for(i=0;i
=0;i--) sa[--ws[wv[i]]]=y[i]; //基数排序部分
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i
= h[i-1]-1 来优化计算height过程
}
char str[N];
int sa[N];
int main(){
char str[N];
scanf("%s",str);
int n = strlen(str);
str[n]=0;
da(str,sa,n+1,128); //注意区分此处为n+1,因为添加了一个结尾字符用于区别比较
calheight(str,sa,n);
}
题目见
后缀数组联系专题
hdu5008-Boring String Problem(后缀数组专题)
后缀数组模板-boj477.新来的小妹妹 & boj477. 田田背课文