后缀数组
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]); }
以上是关于后缀数组的主要内容,如果未能解决你的问题,请参考以下文章