RMQ算法
2021/7/31 17:07:41
本文主要是介绍RMQ算法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
RMQ算法
RMQ(Range Minimun/Maximum Query),即区间查询最值,适用于需要多次查询区间最值的问题。RMQ需要 \(O(n\log n)\) 的预处理,之后可以在 \(O(1)\) 的时间内处理每次查询。
下面的演示我们以查询最小值为例。
获取ST表 \(O(nlogn)\)
RMQ算法采用倍增的思想,设 \(st[i][j]\) 表示区间 \([i, i + 2 ^ j - 1]\) 中的最值,即 \(i\) 后 \(2^j\) 个数字的最值。我们可以把区间分为两半 \([i,i+2^{j-1}-1]\) 和 \([i+2^{j-1},i+2^j-1]\),则最值可以表示为这两个子区间的最值,显然这两个区间最值为 \(st[i][j-1]\) 和 \(st[i+(1<<j-1))][j-1]\) 。则状态转移方程为:
\[st[i][j] = min(st[i][j-1], st[i+2^{j-1}][j-1]) \]我们把这个数组记为\(st\)表,于是我们得出代码:
Code
void RMQ () { for (int i = 1; i <= n; i++) st[i][0] = a[i]; // 边界处理 for (int j = 1; (1 << j) <= n; j++) for (int i = 1; i + (1 << j) - 1 <= n; i++) st[i][j] = min(st[i][j-1], st[i+(1<<j-1)][j-1]); }
注意,状态转移方程是从小区间转移到大区间,所以我们要先处理小区间。也就是范围要先循环。
如何查询\([l, r]的最值\) \(O(1)\)
由于\(st\)表是由倍增构建的,所以只能存储2的幂次方长度的区间最值,那么我们要怎么求任意区间的最值呢?
同样的,我们把区间分为两段,\([l,l+2^k-1]\) 和 \([r-2^k+1,r]\),这里k表示长度不超过\(r-l+1(查询区间的长度)\)的倍增区间的倍增幂指数。如下图:
显然,查询的区间最值只需要在这两个子区间中求出最值即可,即:
\[Minimum = min(st[i][k], st[r-2^k+1][r]); \qquad k = log2(r-l+1) \]Code
int query (int l, int r) { int k = log2(r-l+1); return min(st[i][k], st[r-(1<<k)+1][k]); }
这篇关于RMQ算法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-21MQ-2烟雾传感器详解
- 2024-12-09Kafka消息丢失资料:新手入门指南
- 2024-12-07Kafka消息队列入门:轻松掌握Kafka消息队列
- 2024-12-07Kafka消息队列入门:轻松掌握消息队列基础知识
- 2024-12-07Kafka重复消费入门:轻松掌握Kafka消费的注意事项与实践
- 2024-12-07Kafka重复消费入门教程
- 2024-12-07RabbitMQ入门详解:新手必看的简单教程
- 2024-12-07RabbitMQ入门:新手必读教程
- 2024-12-06Kafka解耦学习入门教程
- 2024-12-06Kafka入门教程:快速上手指南