思路:我们用倍增思想,先比较长度为 2 的子串,再利用该结果比较长度为 4 的子串,再利用该结果比较长度为 8 的子串 … ( 长度为 1 的子串不用比较,因为自身的 ASCII 值就已经相当于比较了)
( 如果 剩余字符 不足 长度 2^k ,则表示到 字符串S的末尾 )
我们应该怎么利用上次比较的结果呢,比如长度为 k 的子串我们已经比较好了,那么长度为 2 * k 的子串,我们就只用看 i 开头长度为 k 的子串排序序号,和 i + k 开头长度为 k 的子串排序序号,然后比较序号之间就行,这样就把字符串之间的比较,转换成了数字比较
复杂度为 O( n * log n * log n )
代码如下:
string S;
int sa[105], rk[105], tmp[105];
int k;
bool cmp(int a, int b)
{
if(rk[a] == rk[b])
{
int i = a + k <= S.length() ? rk[a + k] : -1;
int j = b + k <= S.length() ? rk[b + k] : -1;
return i < j;
}
return rk[a] < rk[b];
}
void construct_sa()
{
for(int i = 0; i <= S.length(); i++)
{
sa[i] = i;
rk[i] = i < S.length() ? S[i] - ‘a’ + 1 : 0;
}
for(int i = 1; i <= S.length(); i = i * 2)
{
k = i;
sort(sa, sa + S.length() + 1, cmp);
tmp[sa[0]] = 0;
for(int i = 1; i <= S.length(); i++)
{
tmp[sa[i]] =