《后缀数组》
1:后缀排序。
基于倍增和桶排的做法。
对于每个位置有第一关键字和第二关键字。
利用倍增来求解关键字,当所有人的排名都不一样时即完成。
2:LCP
最长公共前缀,非常有用。
洛谷:
P3809 【模板】后缀排序
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 1e6 + 5; const int M = 1e3 + 5; const LL Mod = 1000000; #define pi acos(-1) #define INF 1e12 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; char s[N]; int x[N],y[N],c[N],sa[N],rk[N],height[N],n,m; //x - 第一关键字,y - 第二关键字,c - 桶,sa - 排名为i的后缀编号的首位下标,rk - 编号为i的后缀的排名,height[i] = LCP(i,i - 1),LCP - 最长公共前缀 void SA() { for(int i = 1;i <= n;++i) x[i] = s[i],c[x[i]]++;//桶统计 for(int i = 2;i <= m;++i) c[i] += c[i - 1];//前缀和 for(int i = n;i >= 1;--i) sa[c[x[i]]--] = i; for(int k = 1;k <= n;k = (k << 1)) {//倍增 int num = 0; for(int i = n - k + 1;i <= n;++i) y[++num] = i;//后k位不存在 for(int i = 1;i <= n;++i) { if(sa[i] > k) { y[++num] = sa[i] - k;//可做其他的第二关键字 } } for(int i = 1;i <= m;++i) c[i] = 0; for(int i = 1;i <= n;++i) c[x[i]]++; for(int i = 2;i <= m;++i) c[i] += c[i - 1]; for(int i = n;i >= 1;--i) sa[c[x[y[i]]]--] = y[i],y[i] = 0;//更新sa swap(x,y); num = 1,x[sa[1]] = 1; for(int i = 2;i <= n;++i) {//更新x数组 if(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = num; else x[sa[i]] = ++num; } if(num == n) break;//满足所有排名都不一样退出。 m = num; } for(int i = 1;i <= n;++i) printf("%d%c",sa[i],i == n ? '\n' : ' '); } void LCP() { int k = 0; for(int i = 1;i <= n;++i) rk[sa[i]] = i;//初始化rk for(int i = 1;i <= n;++i) { if(rk[i] == 1) { height[1] = 0; continue; } if(k) k--;//更新k int j = sa[rk[i] - 1]; while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++; height[rk[i]] = k; } for(int i = 1;i <= n;++i) printf("%d%c",height[i],i == n ? '\n' : ' '); } int LCP(int x,int y){//LCP(x,y) = min(height[k]) (x < k <= y) int ans = INF; for(int i = x + 1;i <= y;++i) { ans = min(ans,height[i]); } return ans; } int main() { scanf("%s",s + 1); n = strlen(s + 1); m = 122; SA(); system("pause"); return 0; }