写在前面
首先要知道后缀数组的作用:将字符串的每一个后缀按照字典序进行排序,当然我们还可以进行其他的操作们可以求解相邻两个后缀之间最长的公共前缀的长度(LCP问题)
后缀数组
首先我们要明白基数排序,如果不明白的话可以看一下我的另一篇博客:基数排序的实现
当我们明白了基数排序之后,我们就可以看一下后缀数组的模板了:
//不怕别人比你聪明,就怕别人比你聪明还比你努力
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include <set>
#include <stack>
#include <map>
#include<vector>
#include <iterator>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int MAXN = 500;
int n,w;
char str[MAXN];
int SA[MAXN];
int buc[MAXN];
int x[MAXN],y[MAXN],len;
//x数组表示第一元素,y数组表示第二元素
void da()
{
//SA表示我排在第几位的是谁,SA[k] = i,排在第k位的是第i个后缀
scanf("%s",str);
len = strlen(str);
int m = 127;//m表示第一次我们字符串的范围
//在进行倍增之前首先对每一个元素进行一次基数排序,然后放到数组SA中
for(int i =0 ;i < m;i ++) buc[i] = 0;
for(int i =0 ;i < len;i ++) buc[x[i] = str[i]] ++;
for(int i = 1;i < m;i ++) buc[i] += buc[i-1];
for(int i = len-1;i >= 0;i --) SA[ -- buc[x[i]]] = i;
for(int k = 1;k <= len; k <<= 1) //进行倍增
{
int p = 0;
for(int i = len - 1; i >= len -k; i --) y[p++] = i; //我们要得到第二元素,因为要向后移动k个,所以这里表示的是添零操作
//因为零一定会排在最前面,所以y[p++] = i;表示排在第p位的是第i个后缀,表示的就是最后面的后缀
for(int i = 0;i < len;i ++) if(SA[i] >= k) y[p++] = SA[i] - k; //然后我们删除前面几个跳过的元素,这些跳过的元素都是在k之前的,也就是SA[i] < k
//比如我们要排序的数是:92,81,30,24,57,96;