RMQ算法 (区间最值问题)

 首先先介绍一下RMQ算法,RMQ算法是针对区间最值的一个算法,有些问题可以用线段树实现但是你不觉得 有些问题RMQ仅仅几行的代码机上超级快的查询速度是一件很美好的事情吗?!!!!

RMQ原理:定义一个二维数组dp[i][j],表示的是从第i个元素开始,长度(1<<j)内的最值,我们用动态规划的思想来实现

dp[i][j]=max{dp[i][j-1],dp[i+(1<<(j-1))][j-1];

dp[i][j]=min{dp[i][j-1],dp[i+(1<<(j-1))][j-1];

实现代码如下

void RMQ(int num) //预处理->O(nlogn)
{
    for(int i=1;i<=num;i++)
        dp[i][0]=a[i];
    for(int j = 1; (1<<j) <= num; ++j)
        for(int i = 1; i + (1 << j) - 1 <= num; ++i)
            {
                dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
            }
}
之所以j在上i在下 我们得明白我们是先给第i个位置确定了一个初值,然后我们只能

从已经有了的值去推出值 所以只能慢慢来从短到长 由已知到未知 大家好好思考一下这个问题。

接着就是查询了,查询的思路很简单就是找到一个最大的k使(1<<k)<=r-l+1;

int query(int l,int r)
{
    int k=0;
    while(1<<(k+1)<=r-l+1)
        k++;
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
查询的时间复杂度只有O(1) 。

最后我们来看一道例题  NYOJ119:http://acm.nyist.net/JudgeOnline/status.php?pid=119

代码如下 :

#include <iostream>
#include <cstdio>
using namespace std;
int n,m;
int maxsum[100000][20];
int minsum[100000][20];
void RMQ(int num) //预处理->O(nlogn)
{
    for(int j = 1; (1<<j) <= num; ++j)
        for(int i = 1; i + (1 << j) - 1 <= num; ++i)
            {
                maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]);
                minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]);
            }
}
int query(int l,int r)
{
    int k=0;
    while(1<<(k+1)<=r-l+1)
        k++;
    return max(maxsum[l][k],maxsum[r-(1<<k)+1][k])-min(minsum[l][k],minsum[r-(1<<k)+1][k]);
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int x;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            maxsum[i][0]=x;
            minsum[i][0]=x;
        }
        RMQ(n);
        int l,r;
        while(m--)
        {
            scanf("%d%d",&l,&r);
            printf("%d\n",query(l,r));
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值