数据结构专题小结:RMQ问题

本文聚焦于RMQ问题,即如何设计数据结构以高效查询给定数组中一段区间的最小值。Tarjan的Sparse-Table算法被介绍,其预处理时间为O(N*logN),查询时间仅为O(1)。算法基于分治思想,通过d(i,j)表示以i开始,长度为2^j的子序列最小值,构建查询表。查询操作通过找到覆盖[L,R]的最长2的幂次区间进行。" 113719228,10536647,Redis主从与哨兵模式详解:确保高可用与数据一致,"['数据库', 'Redis', '主从集群', '哨兵', '高可用']
摘要由CSDN通过智能技术生成

RMQ问题

范围最小值问题(Range Minimum Query)是指:给定一个n个元素的数组A[1],A[2]...A[n]。设计一个数据结构,支持查询操作Query(L,R):计算min{A[L],A[L+1]...A[R]}。

该问题在实践中常用Tarjan的Sparse-Table算法。它的预处理时间是O(N*logN),但查询只需要O(1),而且常数非常小。最重要的是,这个算法非常好写,而且不易写错。

(1)原理:该算法利用了分治法的思想,令d(i,j)表示从i开始的,长度为2^j的一段元素中的最小值。则不难发现如下公式成立:

d(i,j)=min{d(i,j-1),d(i+2^(j-1),j-1)}

注意到2^i≤n,因此d数组的元素个数不超过n*logn个,而每一项都能在常数时间内算完。因此总的时间复杂度是O(N*logN)。

#define N 1000
int d[N][N];
vector<int>A;
#define INF 100000000
void RMQ_init(const vector<int>&A)//初始化操作,所有元素放到vector中
{
	for (int i = 0; i < N;i++)
	for (int j = 0; j < N; j++)
		d[i][j] = INF;
	int n = A.size();
	for (int i = 0; i < n; i++)
		d[i][0] = A[i];
	for (int j = 1; (1 << j) <= n;j++)
	for (int i = 0; i + (1 << j) - 1 < n; i++)
		d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][i - 1]); 
}

查询操作也很简单,令k为满足2^k≤R-L+1的最大整数,则以L开头,以R结尾的两个长度为2^k的区间合起来即覆盖了查询区间[L,R]。由于是最小值,有些元素重复考虑了也没有关系。

 

int RMQ(int L, int R)
{
	int k = 0;
	while ((1 << (k + 1)) <= R - L + 1)k++;
	return min(d[L][k], d[R - (1 << k) + 1][k]);
}

更简洁的写法如下:

 

int RMQ(int L, int R)
{
	int k = log((double)(R - L + 1)) / log(2.0);
	return min(d[L][k], d[R - (1 << k) + 1][k]);
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值