浅谈RMQ算法

本文介绍了RMQ(Range Minimum/Maximum Query)算法,详细阐述了其原理、预处理过程和查询操作,揭示了其在区间最值查询问题中的高效性。尽管RMQ算法不支持修改且仅适用于查找最大值或最小值,但它能在O(log2(n))时间内预处理并以O(1)复杂度进行单点查询,适合优化常数。文中还提供了洛谷P1816题作为实践例子。

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

前言

这篇文章,是一篇总结RMQ算法的一篇文章,若有疑问或建议,请于下方留言,谢谢!

RMQ是什么?

RMQ(Range Minimum/Maximum Query),即区间最值查询。

是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。

这两个问题是在实际应用中经常遇到的问题,而RMQ算法是解决这两种问题的比较高效的算法。

当然,该问题也可以用线段树解决,算法复杂度为:O(N)~O(logN),而线段树代码远远比我们今天讨论的RMQ要长要难理解的多,这里我们暂不介绍。

我们遇到这种区间最值查询问题的时候,通常会想到两种想法

每次查询时暴力扫描区间,时间复杂度单次查询O(n),n次查询便是O(n^2),超过1e4基本上就TLE了
开一个二维数组(空间复杂度O(n*n)),预处理答案在数组中,预处理复杂度O(n^2),单次查询O(1)。
显然这些算法都是渣渣,慢的要死,那么有什么搞基高级的方法来解决这一类问题呢?

答案是倍增思想。(大概是这样的)

RMQ算法描述

我们以最大值来诠释RMQ算法

  1. 令A[i]存储我们要求的数列,F[i][j]表示从第i个位置开始,往后的2^j-1个数字中,最大的数字是多少。
  2. 预处理F数组,对j从大到小枚举。每次处理F[i][j]的时候,F[i][0~j-1]都已经处理好了,那么F[i][j]=max(F[i][j-1],F[i+2^(j-1)][j-1]),因为j最大到log2n,所以预处理的操作的时间复杂度为O(nlog2(n))。
  3. 有了F数组啦,现在我们查询的话就很简单了。比如说我们查询区间(i,j),那么我们令k =⌊log2(i)+j-1⌋,那么我们查询的结果就是max(F[i][j],F[j-(2^k)+1][k]),可以明显看到时间复杂度为O(1)的,而且保证能够覆盖到整个区间。

代码描述如下

预处理操作

void init_rmq(int m) {
    for(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值