ST表详解

相关概念

  • ST表,又名稀疏表,是一种基于倍增思想,用于解决可重复贡献问题的数据结构

倍增:是一种思想,顾名思义,成倍的增加。例如STL库中的vector,之所以称为动态数组,在不指定大小的情况下,初始化为1个空间,而其空间变化规律为1, 2, 4……当添加一个新元素时,如果空间不够,则空间成倍扩大,如下图所示
在这里插入图片描述

可重复贡献问题 是指对于运算op,满足 x op x = x,则对应的区间询问就是一个可重复贡献问题。
例如,最大值有 max(x,x) = x,gcd 有 gcd(x,x) = x,所以 RMQ 和区间 GCD 就是一个可重复贡献问题。

应用场景

  • ST表可用于解决RMQ问题,即区间最值问题

RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值

原理(以求最大值为例)

  • ST表中定义了一个二维数组f[N][M],f[i][j]表示区间[i, i + 2j + 1]内的最大值
  • 根据倍增思想,给出状态转移方程f[i][j] = max(f[i][j - 1], f[i + 2^j - 1^][j - 1])

f[i][j]对应区间[i, i + 2j + 1],长度为2j,若想求该区间内的最大值,则可以将该区间划分为两个等长的区间,长度均为2j / 2 = 2j-1,求每个区间的最大值,再取两者的max即可
由于不同区间有重叠部分,因此从最左侧的区间开始寻找,在后续遍历时会用到前面的结果
在这里插入图片描述
在这里插入图片描述

代码实现

ST表的创建

首先需要确定最大区间长度,以确定f[i][j]中i和j的取值范围
假设数组的长度为n,则有2k <= n < 2k+1,由此可得k = [log2(n)](以2为底n的对数,向下取整)

void ST_Init()
{
	for(int i = 1; i <= n; i ++) f[i][0] = a[i]; //f[i][j],当j为0时,区间长度2^j为0,则区间最大值就是区间的唯一元素a[i] 
	int k = log2(n); //使用math.h库的函数,计算i和j的取值范围 
	for(int j = 1; j <= k; j ++) //之前已经计算过区间长度为0的情况,这里区间长度由2^1 到 2^k 
	{
		for(int i = 1; i <= n - (1 << j) + 1; i ++) //确定区间左端点,区间范围为[i, i + 2^j - 1],所以 i + 2^j - 1 <= n
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); //状态转移方程 
	}
}

时间复杂度O(nlogn)

ST表的查询

对于给定的区间[l, r],首先确定k值,区间长度为r - l + 1,则有2k <= r - l + 1 < 2k+1,再将整个区间分为前2k个数,和后2k个数,分别求出最值,再取二者的max

这里我们会发现,划分的两个区域可能会有重叠部分,如[1, 2, 5, 8, 6]划分为[1, 2, 5]和[5, 8, 6]两个部分,第一个区间最大值为5,第二个区间最大值为8,最终得到的整个区间最大值为8。由此可见,区间重叠对整个区间最大值无影响

int ST_Query(int l, int r)  
{
	int k = log2(r - l + 1);
	return max(f[l][k], f[r - (1 << k) + 1][k]);
} 

时间复杂度O(1)

相关题目

ST表模板题
附近最小

总结

ST表可在O(nlogn)的时间内,查询到给定区间的最值,速度非常快。但缺点时,该过程中,整个数组的元素不能发生变化,否则,每发生一次变化,就要进行一次初始化

欢迎大家批评指正!!!

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值