后缀数组模板详解。
来源:互联网 发布:vender软件 编辑:程序博客网 时间:2024/06/03 18:21
给定一个字符串S,比如它是(abcad),那么它的后缀有”abcad“ ,"bcad ", "cad", "ad", "d", ""。 讲这些后缀字符串按照字典序排序,得到的就是后缀数组。如果用普通的排序方法,排序要o(nlogn),但是每两个字符比较大小要O(n),所以是o(n × n log n)的复杂度。但是利用特殊的算法可以将其降到o(nlogn)。
该算法的思想是,先将每个后缀数组按照只考虑头一个字符,排序, 再将其按照只考虑头两个字符排序,然后是头4个,然后是8个,直到考虑n个。
#include <iostream>#include <stdio.h>#include <cstring>#include <algorithm>using namespace std;#define Max_N (200000 + 100)int n;int k;
int rank1[Max_N], tmp[Max_N];int sa[Max_N];// n为字符长度, rank1[[i] 表示的是以第i个字符开头的后缀数组的排名, sa[i] 是排在i位的后缀数组的开头字符的位置。bool compare_sa(int i, int j){if(rank1[i] != rank1[j]) return rank1[i] < rank1[j];else {int ri = i + k <= n ? rank1[i + k] : -1;int rj = j + k <= n ? rank1[j + k] : -1;return ri < rj;}}void construct_sa(string buf){n = buf.length();for (int i = 0; i <= n; i++) {sa[i] = i;rank1[i] = i < n ? buf[i] : -1;}for ( k = 1; k <= n; k *= 2) {sort(sa, sa + n +1, compare_sa);tmp[sa[0]] = 0;for (int i = 1; i <= n; i++) {tmp[sa[i]] = tmp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);}for (int i = 0; i <= n; i++) {rank1[i] = tmp[i];}}}int main(){ string str;cin >> str;construct_sa(str);for (int i = 0; i <= n; i++) {cout << sa[i] << endl;}cout << endl;for (int i = 0; i <= n; i++) {cout << rank1[i] << endl;}return 0;}
cd3算法,没怎么理解, 所以只能照敲了模板,保存一发。
cd3的算法虽然是线性的o(n) 的,但是其前面的常数特别大而且会占用大量内存,相对于倍增算法的o(nlogn)优势也不是很大,只要题目不是特别特殊,倍增算法都可以解决。
#include <iostream>#include <stdio.h>#include <cstring>#include <algorithm>using namespace std;#define Max_N 1000#define F(x) ((x)/3+((x)%3==1?0:tb))#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) int wa1[Max_N*3], wb1[Max_N*3], wv1[Max_N*3], ws1[Max_N*3]; int c0(int *r, int a, int b) {return r[a] == r[b] && r[a+1] == r[b+1] && r[a+2] == r[b+2];}int c12(int k, int *r, int a, int b) {if(k == 2) return r[a] < r[b] || r[a] == r[b] && c12(1, r, a+1, b+1); else return r[a] < r[b] || r[a] == r[b] && wv1[a+1] < wv1[b+1];} void sort(int *r, int *a, int *b, int n, int m) { int i; for (i = 0; i < n; i++) wv1[i] = r[a[i]]; for (i = 0; i < m; i++) ws1[i] = 0; for (i = 0; i < n; i++) ws1[wv1[i]]++; for (i = 1; i < m; i++) ws1[i] += ws1[i-1]; for (i = n-1; i >= 0; i--) b[--ws1[wv1[i]]] = a[i]; return; }void dc3(int *r, int *sa, int n, int m){int i, j, *rn = r + n, *san = sa + n,ta = 0,tb = (n + 1) / 3,tbc = 0,p; r[n] = r[n+1] = 0; for (i = 0; i < n; i++) if (i % 3 != 0) wa1[tbc++] = i; sort(r+2, wa1, wb1, tbc, m); sort(r+1, wb1, wa1, tbc, m); sort(r, wa1, wb1, tbc, m); for (p = 1,rn[F(wb1[0])] = 0,i = 1;i < tbc; i++) rn[F(wb1[i])] = c0(r, wb1[i-1], wb1[i]) ? p - 1 : p++; if (p < tbc) dc3(rn, san, tbc, p); else for (i = 0; i < tbc; i++) san[rn[i]] = i; for (i = 0; i < tbc; i++) if (san[i] < tb) wb1[ta++] = san[i] * 3; if (n % 3 == 1) wb1[ta++] = n - 1; sort(r, wb1, wa1, ta, m); for (i = 0; i < tbc; i++) wv1[wb1[i] = G(san[i])] = i; for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++) sa[p] = c12(wb1[j] % 3, r, wa1[i], wb1[j]) ? wa1[i++] : wb1[j++]; for(; i < ta; p++) sa[p] = wa1[i++]; for(; j < tbc; p++) sa[p] = wb1[j++]; return; }// str sa 都要开三倍的;void da(int str[], int sa[], int rank1[], int height1[], int n, int m){for (int i = n; i < n*3; i++)str[i] = 0;dc3(str, sa, n+1, m);int i, j, k = 0;for (i = 0; i <= n; i++) rank1[sa[i]] = i;for (i = 0; i < n; i++){if (k) k--;j = sa[rank1[i] - 1];while (str[i+k] == str[j+k]) k++;height1[rank1[i]] = k;}return;}int str[3*Max_N];int sa[3*Max_N];int rank1[3*Max_N];int height1[3*Max_N];int main(){char buf[100];cin >> buf;int n = strlen(buf);//cout << n << endl;int m = 128;for (int i = 0; i < strlen(buf); i++)str[i] = int(buf[i]);str[n] = 0;da(str, sa, rank1, height1, n, m);for (int i = 0; i <= n; i++)cout << sa[i] << endl;return 0;}
阅读全文
1 0
- 后缀数组详解+模板
- 后缀数组模板详解。
- 后缀数组模板及代码详解
- 后缀数组倍增算法模板详解
- 【后缀数组】后缀数组模板
- 后缀数组【模板】
- 【后缀数组模板】
- 后缀数组模板
- 后缀数组模板
- 【模板】后缀数组
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 【省选】【后缀数组】模板
- 后缀数组 模板
- 后缀数组 模板
- 后缀数组模板
- 后缀数组模板
- 页面实现图片传输放大预览JS
- 工作-2017.07.30-周记总结篇(一)
- centos的/etc/rc.d下的rc.local没有生效的问题
- 各种排序之间的比较和实现
- C语言中使用静态函数的好处
- 后缀数组模板详解。
- 记一次Build.gradle引发的ClassNotFound
- URAL1004---Sightseeing trip (Floyed求最小环)
- OpenCV之meanshift分割详解
- OpenCV函数threshold的使用
- jqGrid初级入门知识整理
- 弟弟的作业
- luogu1004 【2000提高】方格取数(dp)
- opencv石头剪刀布