博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
初识后缀数组
阅读量:6605 次
发布时间:2019-06-24

本文共 2212 字,大约阅读时间需要 7 分钟。

推荐博客:

 

所谓的后缀数组,就是将字符串的 n 个后缀全部取出来,采用字典序的排序方式,将排序好的后缀开头位置顺次放进数组中。

在后缀数组中,有几个关键的变量

1 . SA 数组,若 sa[ i ] = j ,所表示的含义是排名为 i 的后缀起始下标是 j ,

2 . rank数组,若rank[ i ] = j,所表示的含义是以 i 为开头的后缀的排名是 j,

3 . height数组,所表示的suffix(sa[i])和suffix(sa[i-1])的最长公共前缀,即排名相邻的两个后缀的最长公共前缀

4 .h数组, 所表示的含义是 h[i] = height[rank[i]],即 suffix(i)和在有序数列中排在它前一名后缀的最长公共前缀。

 suffix(j) 和 suffix(k)的最长公共前缀为 min(height[rank[j]+1], height[rank[j]+2], … height[rank[k]])

 

接下来就是构造后缀数组,有两种方法,一种是倍增的算法(n*logn)

const int maxn = 2e4+5;/*-待排序数组长度为 n,放在 0~n-1,在最后加一个'$',让其比所有的字符串中的字符都小,这样既可以满足字典序的要求,也不越界*build_sa( ,n+1, );//注意是n+1;*getheight(,n);*例如:*n   = 8;*num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0*rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值*sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值*/int n; int a[maxn], s[maxn];int sa[maxn], rank[maxn], height[maxn];int t1[maxn], t2[maxn], c[maxn];bool cmp(int *r, int a, int b, int l){    return r[a] == r[b] && r[a+l] == r[b+l]; // !!!}void build_sa(int n, int m){ //m代表估计数字,是ASCll的最大值    int *x = t1, *y = t2;        for(int i = 0; i < m; i++) c[i] = 0;    for(int i = 0; i < n; i++) c[x[i]=s[i]]++;    for(int i = 1; i < m; i++) c[i] += c[i-1];    for(int i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;        for(int j = 1; j <= n; j <<= 1){  // !!!        int p = 0;        for(int i = n-j; i < n; i++) y[p++] = i;        for(int i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i]-j;                for(int i = 0; i < m; i++) c[i] = 0;        for(int i = 0; i < n; i++) c[x[y[i]]]++;        for(int i = 1; i < m; i++) c[i] += c[i-1];        for(int i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];                swap(x, y);        p = 1; x[sa[0]] = 0; // !!!                for(int i = 1; i < n; i++)             x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;               if (p >= n) break;        m = p; // 下次基数排序的最大值  !!!    }}void getheight(){    int k = 0;    for(int i = 0; i <= n; i++) rank[sa[i]] = i;    for(int i = 0; i < n; i++){        if (k) k--;        int j = sa[rank[i]-1];        while(s[i+k] == s[j+k]) k++;        height[rank[i]] = k;    }}

 

转载于:https://www.cnblogs.com/ccut-ry/p/9048665.html

你可能感兴趣的文章
【转】聚集索引和非聚集索引的区别
查看>>
[C++知识点]2015.4.18
查看>>
第五次作业
查看>>
【转】mac os 安装php
查看>>
关于数据库归档
查看>>
yun install java
查看>>
Android -- OkHttp的简单使用和封装
查看>>
POJ 1991 DP
查看>>
Hibernate 分组查询 子查询 原生SQL
查看>>
软件工程_第二次作业
查看>>
有关vue的一点点收获
查看>>
数据结构之栈与队列
查看>>
centos常用网络管理命令
查看>>
mysql主从配置(基于mysql5.5.x)
查看>>
mysql表时间戳字段设置
查看>>
如何将本地vue项目上传到github
查看>>
极验验证码示例
查看>>
# 基于Gitolite搭建Git Server - 支持SSH&HTTP
查看>>
C# DllImport的用法
查看>>
Flask 中command的使用
查看>>