算法学习:后缀数组 height的求取
【定义】
【LCP】全名最长公共前缀,两个后缀之间的最长前缀,以下我们定义
lcp ( i , j ) 的意义是后缀 i 和 j 的最长前缀
【z函数】 函数z [ i ] 表示的是,第 i 个后缀和字符串的最长前缀
【解决问题】
这两个算法都是在解决这个问题
即求后缀和字符串和后缀之间的最长公共前缀
但是有所不同的是,
后缀数组最终求出的是,字典序第 i 个后缀和第 i + 1 个后缀的最长公共前缀
z函数最终求出的是,第 i 个后缀和字符串的最长公共前缀
然后通过这个最长公共前缀求一些其他的值
【算法学习】
【后缀数组】
后缀数组能够在 n 的时间内求出字典序第 i 和第 i - 1 个后缀的最长公共前缀
而这个函数通常被命名为 height
height [ i ] 的含义为 , 字典序第 i - 1个后缀和第 i 个后缀的最长公共前缀
有以下几个性质进行求取:(s [ i ] 表示第 i 个后缀)
1.若 i 小于 j , LCP ( i , j ) = min { LCP ( k - 1 , k ), i + 1 <= k <= j }
可利用此项用 RMQ 求LCP
2.定义 h [ i ] 为 :第 i 号开始的后缀和他字典序前面的后缀的LCP
即: h [ i ] = height [ rank [ i ] ]
于是有,对于 i > 1 且 rank [ i ] > 1 有
h [ i ] > h [ i - 1 ] - 1 ;
证明如下 :
设 j 为 第 i - 1 号开始的后缀按排名的前面的那个后缀的开始的位置
注意: j 不是第 i - 2号
此时,第 j 个后缀和第 i - 1 个后缀的 LCP 在定义上为 height [ rank [ i - 1 ] ],即 h [ i - 1 ]
即我们要证明的右半部分的一部分
然后我们讨论 j + 1 和 i (由得到 i - 1 + 1 ) 的关系:
第一种,当 j 和 i - 1 首字母不相等的情况,h [ i - 1 ] 为 0
那么显然 h [ i ] > h [ i - 1 ] - 1
第二种,当 j 和 i - 1 首字母相等的情况,
那么显然,j 和 i - 1 的 LCP 为 h [ i - 1 ] - 1
在后缀中,排名比 i 考前,和后缀 i LCP最长的,相似度最高的显然是SA中离他最近的那个
即 SA [ rank [ i - 1] ] - 1
也就是 , h [ i ] >= h [ i - 1 ] - 1
证毕
所以我们每次找最长前缀的时候,都可以从 h [ i - 1 ] 开始检索
可以类比 manacher
代码如下:
void GetHeight() { int j, k = 0; for(int i = 1; i <= N; i++) { if(k) k--; int j = sa[rak[i] - 1]; while(s[i + k] == s[j + k]) k++; Height[rak[i]] = k; printf("%d\n", k); } }
题目:
【SDOI 2008】 Sandy的卡片
原文地址:https://www.cnblogs.com/rentu/p/11338901.html
- 【Oracle12.2新特性掌上手册】-第八卷 PDB的快速创建与移除
- 《机器学习实战》学习笔记(十一):线性回归基础篇之预测鲍鱼年龄
- 你必须要知道CNN模型:ResNet
- CNN模型之SqueezeNet
- YOLO算法的原理与实现
- Batchnorm原理详解
- 【动手实践】Oracle 12.2 新特性:自动的列表分区创建
- AI从业者搞懂---这10种深度学习方法---老婆孩子热炕头
- OpenCV从零基础---检测及分割图像的目标区域
- Spark资源调优
- Tensorflow实战:Discuz验证码识别
- 【动手实践】:Lockdown Profile 的多租户权限控制
- 异步的JavaScript和XML(AJAX)
- JavaScript实现登录注册验证
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Kafka的实现细节
- CentOS7下安装Elasticsearch-7.3.2和Elasticsearch-head
- spring boot oauth2 取消认证
- 日志级别记录规范
- 搭建K8S集群之node节点部署
- ent orm笔记2---schema使用(上)
- ent orm笔记4---Code Generation
- 什么?明明是2020年12月30日显示2021年12月30日?
- JDK1.8HashMap源码学习-数据结构
- JDK1.8HashMap源码学习-初始化
- JDK1.8HashMap源码学习-put操作以及扩容(一)
- 数据科学家极力推荐核心计算工具-Numpy的前世今生(上)
- 什么是运维眼中可部署的软件架构
- 2020-09-03:裸写算法:回形矩阵遍历。
- Java并发编程系列34 | 深入理解线程池(下)