zoukankan      html  css  js  c++  java
  • RMQ求区间最值 nlog(n)

    转载于:http://blog.csdn.net/xuzengqiang/article/details/7350465

    RMQ算法全称为(Range Minimum/Maximum Query)意思是给你一个长度为n的数组A,求出给定区间的最值的下标。当然我们可以采用枚举,但是我们也可以使用线段树来优化,复杂度为(nlogn),但是最好的办法是采用Sparse_Table算法,简称ST算法。他能在进行(nlogn)的预处理后达到n(1)的效率。下面来分析下最大值和最小值,都要用到DP的思想。

    最小值(Mininun):我们可以用F(i,j)表示区间[i,i+2^j-1]间的最小值。我们可以开辟数组来保存F(i,j)的值,例如:F(2,4)就是保存区间[2,2+2^4-1]=[2,17]的最小值。那么F(i,0)的值是确定的,就为i这个位置所指的元素值,这时我们可以把区间[i,i+2^j-1]平均分为两个区间,因为j>=1的时候该区间的长度始终为偶数,可以分为区间[i,i+2^(j-1)-1]和区间[i+2^(j-1)-1,i+2^j-1],即取两个长度为2^(j-1)的块取代和更新长度为2^j的块,那么最小值就是这两个区间的最小值的最小值,动态规划为:F[i,j]=min(F[i,j-1],F[i+2^(j-1),j-1]).同理:最大值就是F[i,j]=max(F[i,j-1],F[i+2^(j-1),j-1]).

    现在求出了F[i,j]之后又是怎样求出最大值或者最小值的,怎么转换为o(1)这种算法的~这就是ST算法:

    这个时候询问时只要取k=ln(j-i+1)/ln2即可,那么可以令A为i到2^k的块,和B为到2^k结束的长度为2^k的块;那么A,B都是区间[i,j]的子区间,所以即求A区间的最小值和B区间的最小值的最小值。这个时候动态规划为:RMQ(i,j)=min(F[i,k],F[j-2^k+1,k]);

    log2的求法:

    Log[0] = -1;
    for(int i = 1;i <M;i++)
       Log[i] = ((i&(i-1)) == 0)?Log[i-1]+1:Log[i-1];
    RMQ:

    void RMQ(int n)
    {
        int i,j;
        int m=Log[n];
        for(i=1;i<=n;i++)
            dp_min[i][0]=dp_max[i][0]=dis[i];//dis代表原数列
        for(j=1;j<=m;j++)
        {
            for(i=1;i<=n+1-(1<<j);i++)
            {
                dp_max[i][j]=max(dp_max[i][j-1],dp_max[i+(1<<(j-1))][j-1]);
                dp_min[i][j]=min(dp_min[i][j-1],dp_min[i+(1<<(j-1))][j-1]);
            }
        }
    }
    最小值:
    int lcp(int x,int y)
    {
        int m=Log[y-x+1];
        return min(dp_min[x][m],dp_min[y+1-(1<<m)][m]);
    }
    最大值

    int lcp(int x,int y)
    {
        int m=Log[y-x+1];
        return max(dp_max[x][m],dp_max[y+1-(1<<m)][m]);
    }




  • 相关阅读:
    linux du命令
    Linux vmstat命令实战详解
    linux sar命令详解
    xargs 命令教程
    Linux中find命令用法大全
    python suprocess
    Python的f-strings格式化
    python glob的使用
    python getopt()的使用
    Java测试的题目感想
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348112.html
Copyright © 2011-2022 走看看