RMQ算法

本文详细介绍了RMQ算法及其应用,并深入探讨了Sparse_Table(ST)算法的原理及其实现过程。通过动态规划的方法,ST算法能够在预处理阶段达到O(nlogn)的时间复杂度,在查询阶段实现O(1)的高效查询。文章还提供了具体的RMQ算法模板代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     RMQ算法全称为(Range Minimum/Maximum Query)意思是给你一个长度为n的数组A,求出给定区间的最值的下标。当然我们可以采用枚举,但是我们也可以使用线段树来优化,复杂度为(nlogn),但是最好的办法是采用Sparse_Table算法,简称ST算法。他能在进行(nlogn)的预处理后达到n(1)的效率。下面来分析下最大值和最小值,都要用到DP的思想。

    最小值(Mininun):我们可以用F(i,j)表示区间[i,i+2^j-1]间的最小值。我们可以开辟数组来保存F(i,j)的值,例如:F(2,4)就是保存区间[2,2+2^4-1]=[2,17]的最小值。那么F(i,0)的值是确定的,就为i这个位置所指的元素值,这时我们可以把区间[i,i+2^j-1]平均分为两个区间,因为j>=1的时候该区间的长度始终为偶数,可以分为区间[i,i+2^(j-1)-1]和区间[i+2^(j-1)-1,i+2^j-1],即取两个长度为2^(j-1)的块取代和更新长度为2^j的块,那么最小值就是这两个区间的最小值的最小值,动态规划为:F[i,j]=min(F[i,j-1],F[i+2^(j-1),j-1]).同理:最大值就是F[i,j]=max(F[i,j-1],F[i+2^(j-1),j-1]).

现在求出了F[i,j]之后又是怎样求出最大值或者最小值的,怎么转换为o(1)这种算法的~这就是ST算法:

这个时候询问时只要取k=ln(j-i+1)/ln2即可,那么可以令A为i到2^k的块,和B为到2^k结束的长度为2^k的块;那么A,B都是区间[i,j]的子区间,所以即求A区间的最小值和B区间的最小值的最小值。这个时候动态规划为:RMQ(i,j)=min(F[i,k],F[j-2^k+1,k]);

RMQ模板

void RMQ_init(const vector<int>& A)
{
	int n = A.size();
	for (int i = 0; i < n; i++)
		dmax[i][0]=dmin[i][0]= A[i]; //初始化
	for (int j = 1; (1 << j) <= n; j++)
		for (int i = 0; i + (1 << j) - 1 <n; i++) { ///i从0开始保证了区间的无缝覆盖
			dmax[i][j] = max(dmax[i][j - 1], dmax[i + (1 << (j - 1))][j - 1]);
			dmin[i][j] = min(dmin[i][j - 1], dmin[i + (1 << (j - 1))][j - 1]);
		}
}
int RMQ_max(int L, int R)
{
	int k = 0;
	while ((1 << (k + 1)) <= R - L + 1) k++;///如果2^(k+1)<=R-L+1,那么看还可以加1
	return max(dmax[L][k], dmax[R - (1 << k) + 1][k]);
}
int RMQ_min(int L, int R)
{
	int k = 0;
	while ((1 << (k + 1)) <= R - L + 1) k++;
	return min(dmin[L][k], dmin[R - (1 << k) + 1][k]);
}


练习题目: 点击打开链接http://acm.nyist.net/JudgeOnline/problem.php?pid=119

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值