后缀数组

Posted nioh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后缀数组相关的知识,希望对你有一定的参考价值。

后缀是从字符串的某个位置到字符串末尾的非空子串。例如:$suff(HORSE) = {E, SE, RSE, ORSE, HORSE}$。
后缀数组是包含字符串所有已排序后缀的数组。例如:$sa(CAMEL) = {1-AMEL, 0-CAMEL, 3-EL, 4-L, 2-MEL} = {1, 0, 3, 4, 2}$。
首先可以想出一种基于快速排序的后缀数组求法,但是时间复杂度为$O(n^2logn)$。可用一种倍增算法来优化,时间复杂度$O(nlogn)$,待补。

后缀数组用于事先不知道模板P的多模板匹配问题,此时需要处理文本串T。
sa是后缀排名到位置的映射
x是第一关键字位置到排名(数值)的映射
y是第二关键字排名到位置的映射
c是基数排序的桶

技术图片

 例题:洛谷P3809

#include<bits/stdc++.h>
using namespace std;

const int N = 1000050;
char s[N], p[N];
int sa[N], x[N], y[N], c[N], n;

void build_sa(int m) {
    n = strlen(s + 1);
    for(int i = 1; i <= n; i++) c[x[i] = s[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 <<= 1) {
        int p = 1;
        for(int i = n - k + 1; i <= n; i++) y[p++] = i;
        for(int i = 1; i <= n; i++) if(sa[i] > k) y[p++] = 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];
        swap(x, y);
        p = 1; x[sa[1]] = 1;
        for(int i = 2; i <= n; i++)
            x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p : ++p;
        if(p == n) break;
        m = p;
    }
}

int main() {
    gets(s + 1);
    build_sa(200);
    for(int i = 1; i <= n; i++) printf("%d ", sa[i]);
}

 

以上是关于后缀数组的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段—— 数组的响应式方法

VSCode自定义代码片段10—— 数组的响应式方法

Sublime Text3自定义代码片段

后缀数组代码详解

●后缀数组○十三个例题

初学后缀数组记录(然而并不是很会。。&&很水。。)