首页 > 其他分享 >后缀数组学习笔记(未完成

后缀数组学习笔记(未完成

时间:2024-03-23 22:56:41浏览次数:30  
标签:后缀 笔记 height int 数组 sa rk

后缀数组定义与实现

定义

后缀

从字符串某个位置i到字符串末尾的子串,定义s的第i个字符为第一个元素的后缀为suf(i)。

后缀数组

把s的每一个后缀按照字典序排序,后缀数组sa[i]表示排名为i的后缀的起始位置的下标。rk[i]数组代表起始位置为i的后缀的排名。

rk[]和sa[] 是一一对应关系,互为逆运算,可以相互推导

倍增

倍增法求后缀数组是从字符串的第一个字符开始比较,然后每次倍增比较长度,直到完成。每次都递增两倍,所以总步骤一共只有 \log_2 n 次,非常高效。

优化

如果字符串很长,包含10000个字符,那么在最后一步,每个数字都有10000位,无法存储与排序。

方法是在每步操作后就对组合数字进行排序,用序号产生一个新数字,再用新数字进行下一步排序。

基数排序即可。

 

height数组

大概是SA里最核心,最有用的部分。

height[i] 表示 suf(sa[i]) 与 suf[sa[i -1]] 的最长公共前缀(LCP)。

性质:height[i] \ge height[rk[i - 1]]-1 。

lcp求解:lcp(i, j) = \min_{k =rk[i]+1}^{rk[j]} height[k]​

 

 

代码

const int N = 1e6 + 7;
int sa[N], rk[N], c[N], x[N], y[N], height[N];

char s[N];
int n, m;

void get_sa() {
   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; i --) sa[c[x[i]] --] = i;
   for(int k = 1; k <= n; k *= 2) {
       int num = 0;
       for(int i = n - k + 1; i <= n; i ++) y[++ num] = i;
       for(int i = 1; i <= n; i ++) {
           if(sa[i] > k) y[++ num] = 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; i --) sa[c[x[y[i]]] --] = y[i], y[i] = 0;
       swap(x, y);
       num = 1, x[sa[1]] = 1;
       for(int i = 2; i <= n; i ++) {
           x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++ num;
      }
       if(num == n) break;
       m = num;
  }
}
void get_height() {
   for(int i = 1; i <= n; i ++) rk[sa[i]] = i;
   int k = 0;
   for(int i = 1; i <= n; i ++ ){
       if(rk[i] == 1) continue;
       if(k) k --;
       int j = sa[rk[i] - 1];
       while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
       height[rk[i]] = k;
  }
}

 

题目

sa数组的应用

P4051 [JSOI2007] 字符加密

把原串拼一个在后面,求出sa数组后,如果这个位置在原串里,那输出对应结尾的字符。

int main() {
   cin >> s;
   n = s.size() * 2;
   s = ' ' + s + s;
   m = 300;
   get_sa();
   for(int i = 1; i <= n; i ++) {
       if(sa[i] <= n / 2) cout << s[sa[i] + n / 2 - 1];
  }
}

height数组的应用

UVA1223 Editor

给定文本字符串 s,查找文本字符串 s 中最长的子字符串,使得子字符串至少出现两次。

对于出现两次的子串,一定是后缀排序后相邻的两个的公共前缀,答案即为对 height 数组取最大值。

void solve() {
   int ans = -1;
   scanf("%s", s + 1);
   n = strlen(s + 1);
   m = 122;
   for(int i = 1; i <= m; i ++) sa[i] = rk[i] = c[i] = height[i] = x[i] = y[i] = 0;
   get_sa();
   get_height();
   for(int i = 1; i <= n; i ++) ans = max(ans, height[i]);
   cout << ans << endl;
}
int main() {
   int T;
   cin >> T;
   while(T --) {
       solve();
  }
}

P2408 不同子串个数

不同字串的个数就是所有的字串减去相同的字串个数。总的字串个数为 \frac{n(n + 1)}{2} 。所有后缀产生的相同的前缀个数为 \sum_{1}^{n} height[rk[i]],相同的字串个数为 \sum_{1}^{n} height[rk[i]]。答案为 \frac{n(n+1)}{2} - \sum_{1}^{n} height[rk[i]]。

 

标签:后缀,笔记,height,int,数组,sa,rk
From: https://www.cnblogs.com/-wwyyyy/p/18091844

相关文章

  • C105 整体二分+树状数组 P2617 Dynamic Rankings
    视频链接:C105整体二分+树状数组P2617DynamicRankings_哔哩哔哩_bilibili  C96树状数组套权值线段树P2617DynamicRankings-董晓-博客园(cnblogs.com)C104【模板】整体二分+树状数组P3834可持久化线段树2-董晓-博客园(cnblogs.com)LuoguP2617Dynamic......
  • 笔记本连接WiFi没有网络
    现象WiFi显示连接,能够登录QQ微信聊天,可以打开部分网页如百度,B站,但是大部分网页提示网络异常,连接超时等,如下图:解决这种问题大概率是因为IP分配的问题,解决办法如下:win+i打开设置选择网络和Internet进去,高级网络设置选择网络重置,立即重置网络重置选......
  • HashMap的数组最大容量为什么要设计为2的30次方?而不是2的31次方-1?数组容量为什么一定
    目录问题 数组容量为什么一定要设计为2的幂(2的n次方)?1、首先要清楚HashMap的底层基本原理2、再来看下怎么通过hash值决定存放在哪个桶中?首先看下hash值再看下怎么确定当前key存放在哪个数组下标下的为什么要做按位与而不用模运算符%?为什么要n-1呢?n是一个什么样的数......
  • 大数据学习笔记7-Mysql高级
    知识点1:DQL之排序查询--排序查询:就是按照指定字段的大小进行排序,排序规则分为升序和降序--升序(ASC):从小到大依次递增--降序(DESC):从大到小依次递减--关键字:orderby--格式:select列...from表where条件orderby排序规则[ASC|DESC];--0.使......
  • 安装OpenStack认证服务组件KeyStone--笔记
       以下笔记根据腾讯专家讲解的《云计算与OpenStack》网络课程,地址:1KeyStone简介_哔哩哔哩_bilibili,整理并亲手操作,特此感谢。 OpenStack框架图 KeyStone简介  早期的OpenStack版本,并没有KeyStone身份认证模块。用户、消息、API调用的认证都是放在Nova模块中的......
  • 严恭敏老师PSINS工具箱学习笔记-3
    惯性传感器测量误差模型参考教材:捷联惯导算法与组合导航原理-严恭敏、翁浚insupdate函数里关于补偿的部分:[phim,dvbm]=cnscl(imu,0);%coning&scullingcompensationphim=ins.Kg*phim-ins.eb*nts;dvbm=ins.Ka*dvbm-ins.db*nts;%calibrationins.wib......
  • Fast-R-CNN论文笔记
    目标检测之FastR-CNN论文精讲,FastRCNN_哔哩哔哩_bilibili一引言1.1R-CNN和SPPNet缺点......
  • 100道面试必会算法-09-最大子数组和(初探动态规划)
    100道面试必会算法-09-最大子数组和(初探动态规划)题目一个整数数组nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。示例1:输入:nums=[-2,1,-3,4,-1,2,1,-5,4]输出:6解释:连续子数组[4,-1,2,1]的和最大,......
  • ALSA学习笔记
            ALSA框架介绍:ALSA-LINUX音频框架学习笔记-CSDN博客        代码参考(博客园):Alsa音频编程【精华】        对原博客代码进行了修改并添加了注释(测试通过,可直接运行),代码包含三个测试用例:1、显示了一些ALSA使用的PCM数据类型和参数;2、添加声......
  • Javascript学习笔记
    Javascript基础   js是什么?         定义       是一种运行在客户端(浏览器)的编程语言,实现人机交互效果      html和css只是标记语言,并没有涉及编程的部分    作用      网页特效(监听用户的一些行为让网页做......