后缀数组

柔情痞子 提交于 2020-02-12 12:08:28

后缀是从字符串的某个位置到字符串末尾的非空子串。例如:$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]);
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!