RMQ算法,是一个快速求区间最值的离线算法,预处理时间复杂度O(n*log(n))查询O(1),所以是一个很快速的算法,当然这个问题用线段树同样能够解决。

问题:给出n个数ai,让你快速查询某个区间的的最值。

算法分析:

(1)预处理

这个算法就是基于DP和位运算符,我们用 dp[i][j] 表示从第 i 位开始,到第 i + 2^j -1 位的最大值或者最小值。

那么我求dp[i][j的时候可以把它分成两部分,第一部分从 i 到 i + 2 ^( j-1 ) - 1 ,第二部分从 i + 2 ^( j-1 )  到 i + 2^j - 1 次方,其实我们知道二进制数后一个是前一个的二倍,那么可以把 i ~i + 2^j  这个区间 通过2^(j-1) 分成相等的两部分, 那么转移方程很容易就写出来了。

转移方程:dp [ i ] [ j ] = max ( dp [ i ] [ j - 1 ] , dp [ i + ( 1 << ( j - 1 ) ) ] [ j - 1 ] )

以求区间最小值为例

void RMQ()
{
for(int i=1;i<=N;i++)
dp[i][0]=a[i]; //初始化, dp[i][0]就表示第i个数字本身
for(int j = 1; (1<<j) <= N; j++)
for(int i = 1; i+(1<<j)-1 <= N; i++)
dp[i][j]=min(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
}

需要注意的是循环的顺序,我们发现外层是j,内层为i

(2)查询

假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂(可以重复,比如查询5,6,7,8,9,我们可以查询5678和6789)

因为这个区间的长度为j - i + 1,所以我们可以取k=log2( j - i + 1),则有:RMQ(A, i, j)=max{ F[i , k], F[ j - 2 ^ k + 1, k] }(可用数学证明,在此不加以论述)

eg. 要求区间[2,8]的最大值,k = log2(8 - 2 + 1)= 2,即求max(F[2, 2],F[8 - 2 ^ 2 + 1, 2]) = max(F[2, 2],F[5, 2]);

需要注意一个地方,就是<<运算符和+-运算符的优先级

比如这个表达式:5 - 1 << 2是多少?

答案是:4 * 2 * 2 = 16。所以我们要写成5 - (1 << 2)才是5-1 * 2 * 2 = 1

最新文章

  1. java中ArrayList 、LinkList区别
  2. java static 关键字
  3. bzoj 1513 [POI2006]Tet-Tetris 3D(二维线段树)
  4. 微信小程序开发之大坑记之post请求
  5. mysql函数操作(3)
  6. 使用ExpandableListView时间轴效果达到
  7. Linux显示内存状态
  8. gitlab安装后吃内存的解决办法
  9. 在linxu机器ansible上运行启动django项目命令
  10. Spring Boot features - Profiles
  11. python 批量替换文件名
  12. 关于class produre
  13. swift - iOS10之后的加速器
  14. RecyclerView打造通用的万能Adapter
  15. CSS 天坑 I - 字体单位
  16. IOS UI总结
  17. SVN版本合并技巧
  18. == vs === in Javascript
  19. 统计一段文章的单词频率,取出频率最高的5个单词和个数(python)
  20. MySQL里执行SHOW INDEX结果中Cardinality的含义

热门文章

  1. Face_to_object_design
  2. 初识 D3.js :打造专属可视化
  3. 基于SVM的字母验证码识别
  4. 解决Establishing SSL connection without server‘s identity verification is not recommended.
  5. MySQL where 条件字句查询
  6. 【Jboss】A RESOURCE POOL IS PERMANENTLY BROKEN!
  7. vxfs(Veritas File System)扩充目录大小
  8. OGG类异常汇总
  9. Vue MVVM模型原理
  10. luogu P4116 Qtree3