探讨RMQ问题之一:ST算法

    RMQ问题:求给定区间极值问题,下面以最大值为例

    ST(Sparse Table)算法基本也是核心的思想是基于区间划分的动态规划,即M[i,j] = max{ M[i,r-1] , M[r,j] }M[i,j] 表示区间[i,j]上的最大值,r位于[i,j]中间。

   故而不知那位大神开发出如下ST算法:

    状态转移方程:M[ i , j ] = max{ M[ i , j-1 ] , M[ i+(1<<j-1) , j-1] }M[ i , j ]表示从下标i开始长度2^j的区间。

    这样,在预处理是只需要按递推的方式计算每个M[ i , j ],约束条件1<<j<=N(区间长度),i+(1<<j)-1<N(区间数目)M[ i ,0 ]初始化为区间第i个元素自身。这样,预处理时间复杂度仅为O(NlgN),空间复杂度也为NlgN

    当查找任意区间[ x , y ]的极值时,只需要先求出最大的k使得1<<k<=(y-x+1),即求小于给定区间长度的最长的2^k区间长度(因为预处理产生的极值区间均为2的幂次长度)。然后,[ x , y ]上的极值必然是[ x , x+(1<<k)-1 ][ y-(1<<k)+1 , y ]两者中的极值。对于任意查询Query,即有:

    Query[x,y]=max{ M[ x , k ] , M[ y-(1<<k)+1 , k ] }O(1)复杂度时间内就可以存预处理数组中查找计算出任意区间的极值。

    因为大多数题目若是涉及到RMQ便是需要多次来SEARCH,所以ST算法在占有一定空间的情况

下能获得较好的时间复杂度。     

    下面是我写的预处理和查询的代码

 10 void Preproccess(void)    //预处理,array为原数组,max_index存放极值元素下标
 11 {   
 12     for(i=0;i<N;i++) max_index[i][0]=i;
 13     for(j=1;(1<<j)<=N;j++)
 14     {   
 15         for(i=0;i+(1<<j)-1<N;i++)
 16         {
 17             if(array[max_index[i][j-1]]>array[max_index[i+(1<<(j-1))][j-1]])
 18                 max_index[i][j]=max_index[i][j-1];
 19             else max_index[i][j]=max_index[i+(1<<(j-1))][j-1];
 20         }
 21     }
 22 }

 23 int Query(int x,int y)    //查询区间[ x , y ]极值
 24 {
 25     int k,l=y-x+1;
 26     for(k=0;(1<<k)<=l;k++);k--;
 27     if(array[max_index[x][k]]>array[max_index[y-(1<<k)+1][k]])
 28         return array[max_index[x][k]];
 29     else return array[max_index[y-(1<<k)+1][k]];
 30 }

转载于:https://my.oschina.net/llmm/blog/91266

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值