#include <cstdio>
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define MAXN 1001
int n,k;//n=strlen(s);
int Rank[MAXN];
int tmp[MAXN];
char s[MAXN];
int lcp[MAXN],sa[MAXN];
/*使用Rank对sa排序*/
bool cmpSa(int i, int j)
{
if(Rank[i] != Rank[j])return Rank[i] < Rank[j];
else
{ /*下面的Rank[t],已经是以t开头长度小于等于k/2的,
sa[i]的名次,只是以i开头的后缀,而长度不同*/
int ri = i+k <=n? Rank[i+k]:-1;
int rj = j+k <= n ? Rank[j+k]:-1;
return ri <rj;
}
}
/*计算SA*/
void consa()
{
/*n=strlen(s); 必要时注明*/
/*初始化sa和rank保证两点
1、Rank[i]表示下标为i的是第几大,必须表示出相对大小,可以直接用字符代表其大小
2、sa[1...n]值为1..n*/
for(int i=0;i<=n;i++){
sa[i]=i;Rank[i] = i < n?s[i]:-1;
}
/*利用长度为k的字符串对长度为2*k的字符串排序*/
for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1开始,因为0*2=0*/
{
sort(sa,sa+n+1,cmpSa);
tmp[sa[0]] = 0; /*此时tmp只是暂存rank*/
for(int i=1;i<=n;i++){
tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);
/*这一句很关键,等号右侧的sa[i]在此循环里表示第i大的长度小于等于k/2的字符串,
从而求出第i大的长度小于等于k的字符串的sa[i]*/
}
for(int i=0;i<=n;i++){
Rank[i] = tmp[i];
}
}
}
void construct_lcp()
{
//n=strlen(s);
for(int i=0; i<=n; i++)Rank[sa[i]]=i;
int h=0;
lcp[0]=0;
for(int i=0;i<n;i++)
{
int j=sa[Rank[i]-1];
if(h>0)h--;
for(; j+h<n && i+h<n; h++)
{
if(s[j+h]!=s[i+h])break;
}
lcp[Rank[i]-1]=h;
}
}
int main()
{
while(1)
{
cout << "The string : ";
cin >> s;
n=strlen(s);
consa();
construct_lcp();
for(int i=0;i<=n;i++)
printf("i=%d sa=%d lcp=%d suffix[sa[%d]]=%s\n",i,sa[i],lcp[i],i,s+sa[i]);
}
return 0;
}
注:我写的lcp比较奇葩一点,lcp[i]指的是suffix(sa[i]),suffix(sa[i+1])的公共前缀的长度