后缀数组 (核心:所有的字串都是某一个后缀的前缀)

各个数组含义

sa[] 名次-》位置

_rank[] 位置-》名次

tp [] 第二关键字  名次-》位置

height[]  两个排名相邻后缀最长公共前缀

性质1 两个后缀(i,j)的最大公共前缀=min (height[_rank[i]+1].....height[_rank[j]] ) (假设排名_rank[i]<_rank[j])

性质2 h[i]>=h[i-1]-1 (h[i] i位置的后缀数组和它前一名的最长公共前缀)

void resort () {//基数排序
    for (int i=0;i<=m;i++) tax[i]=0;
    for (int i=1;i<=n;i++) tax[ _rank[i] ]++;
    for (int i=1;i<=m;i++) tax[i]+=tax[i-1];
    for (int i=n;i>=1;i--) sa[tax[_rank[tp[i]]]--]=tp[i];
}
void build_sa() {
    for (int i=1;i<=n;i++) {
        _rank[i]=a[i];
        tp[i]=i;
    }
    m=27; resort();// 初始化
    for (int w=1,p=1,i;p<n;w+=w,m=p) {
        // 第二关键字排序
        for (p=0,i=n-w+1;i<=n;i++) tp[++p]=i;
        for (i=1;i<=n;i++) if (sa[i]>w) tp[++p]=sa[i]-w;
        //  第一关键字排序 
        resort();
        // 根据sa[]求_rank[] 
        swap(_rank,tp);  _rank[sa[1]]=p=1;
        for (i=2;i<=n;i++) {
            if (tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w]) 
          _rank[sa[i]]=p; else
          _rank[sa[i]]=(++p); } } return ; } void build_height() { int k=0;// height数组 for (int i=1;i<=n;i++) { if (k) k--; int j=sa[_rank[i]-1]; while (str[i+k]==str[j+k]) k++; height[_rank[i]]=k; } return ; }
抓住青春的尾巴。。。
原文地址:https://www.cnblogs.com/xidian-mao/p/8400629.html