1402 后缀数组 0x10「基本数据结构」例题
描述
后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围。在本题中,我们希望使用快排、Hash与二分实现一个简单的 O(n log^2n ) 的后缀数组求法。详细地说,给定一个长度为 n 的字符串S(下标 0~n-1),我们可以用整数 k(0≤k<n) 表示字符串S的后缀 S(k~n-1)。把字符串S的所有后缀按照字典序排列,排名为 i 的后缀记为 SA[i]。额外地,我们考虑排名为 i 的后缀与排名为 i-1 的后缀,把二者的最长公共前缀的长度记为 Height[i]。我们的任务就是求出SA与Height这两个数组。<n) i="" i-1="" p="">
输入格式
一个字符串,长度不超过30万。
输出格式
第一行为数组SA,相邻两个整数用1个空格隔开。
第二行为数组Height,相邻两个整数用1个空格隔开,特别地,假设Height[1]=0。
样例输入
ponoiiipoi
样例输出
9 4 5 6 2 8 3 1 7 0 0 1 2 1 0 0 2 1 0 2
样例解释
排名第一(最小)的后缀是9(S[9~9],即字符串 i),第二的是后缀4(S[4~9],即字符串iiipoi),第三的是后缀5(S[5~9],即字符串iipoi)以此类推。Height[2]表示排名第2与第1的后缀的最长公共前缀,长度为1,Height[3]表示排名第3与第2的后缀的最长公共前缀,长度为2,以此类推。
题意:
给一个字符串s的所有后缀按字典序排个序得到的就是后缀数组。求出排名第i的和排名第i-1的最长公共前缀长度,为height数组
思路:
依旧是Hash整个字符串,根据Hash值二分找到两个子串的最长公共子串,以此作为sort的比较依据
发现大佬们都是不用结构体的,写的很巧妙啊。
这种方法求后缀数组的复杂度是O(n(logn)^2)
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <map> 8 using namespace std; 9 typedef long long LL; 10 #define inf 0x7f7f7f7f 11 12 const int maxn = 3e5 + 10; 13 char s[maxn]; 14 unsigned long long H[maxn], p[maxn]; 15 int sa[maxn], rk[maxn], height[maxn], n; 16 17 18 unsigned long long getH(int i, int j) 19 { 20 return H[j] - H[i - 1] * p[j - i + 1]; 21 } 22 23 24 //二分求最长公共前缀长度 25 int lcp(int x, int y) 26 { 27 int l = 0, r = min(n - x + 1, n - y + 1); 28 while(l < r){ 29 int mid = (l + r + 1) / 2; 30 if(getH(x, x + mid - 1) == getH(y, y + mid - 1)){ 31 l = mid; 32 } 33 else{ 34 r = mid - 1; 35 } 36 } 37 return l; 38 } 39 40 bool cmp(int x, int y) 41 { 42 int l = lcp(x, y); 43 return s[x + l] < s[y + l]; 44 } 45 46 int main() 47 { 48 scanf("%s", s + 1); 49 n = strlen(s + 1); 50 p[0] = 1; 51 for(int i = 1; i <= n; i++){ 52 sa[i] = i; 53 H[i] = H[i - 1] * 131 + s[i] - 'a' + 1; 54 p[i] = p[i - 1] * 131; 55 } 56 sort(sa + 1, sa + n + 1, cmp); 57 for(int i = 2; i <= n; i++){ 58 height[i] = lcp(sa[i - 1], sa[i]); 59 } 60 for(int i = 1; i <= n; i++){ 61 printf("%d ", sa[i] - 1); 62 } 63 printf(" "); 64 for(int i = 1; i <= n; i++){ 65 printf("%d ", height[i]); 66 } 67 printf(" "); 68 69 return 0; 70 }