zoukankan      html  css  js  c++  java
  • static RMQ

    RMQ问题:对于长度为N的序列,询问区间[L,R]中的最值

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

    常见解法:

    1.朴素搜索

    2.线段树

    3.DP

    4.神奇的笛卡尔树(https://www.cnblogs.com/jklongint/p/4777448.html?utm_source=tuicool

    1.朴素搜索

    max=a[L];
    for(int i=L+1;i<=R;i++)
      if(max<a[i])
        max=a[i];
    }

    2.线段树https://www.cnblogs.com/jason2003/p/9676729.html

    大概就是玩区间,将一个区间分为很多个小区间,分治的思想。

    public class TestE {
        
    
        public static void main(String[] args) {
            int[]a= {3,4,5,1,2};
            SenLin sl=new SenLin(a);
            sl.buildTree(0, 4, 1);
            System.out.println(sl.search(0, 4, 1));
        }
        
    }
    class SenLin{
        
        Tree[]N=new Tree[300];
        int[] values;
        
        public SenLin(int[]values) {
            this.values=values;
        }
        public void buildTree(int l,int r,int u) {
            N[u]=new Tree();
            N[u].l=l;N[u].r=r;
            if(l==r) {
                N[u].max=values[l];
                return;
            }
            buildTree(l,r+l>>1,2*u);
            buildTree((r+l>>1)+1,r,2*u+1);
            N[u].max=Math.max(N[2*u].max, N[2*u+1].max);
        }
        public int search(int l,int r,int u) {
            if(N[u].l==l&&N[u].r==r)    
                return N[u].max;    
            if(r<=N[2*u].r)    //在左孩子的范围里    
                return search(l,r,2*u);    
            if(l>=N[2*u+1].l)//在右孩子的范围里
                return search(l,r,2*u+1);    
            int mid=(N[u].l+N[u].r)>>1;    
            return Math.max(search(l,mid,2*u),search(mid+1,r,2*u+1));
        }
    }
    class Tree{
        int l;
        int r;
        int max;
    }

    3.DP

    3.1预处理(时间复杂度O(nlogn))

    建立dp数组,dp[i][j]表示从i开始长度为2j的区间中的最值(DP的状态)。当dp[i][0]就是从i开始长度为1的区间,就是它本身。(DP的初始值)

    目的是将求从i长度为2j的大问题可以分为两个长度为2(j-1)的小问题,即[i,i+2j-1-1],[i+2j-1,i+2j-1+2j-1-1]=[i+2j-1,i+2j-1]。

    因为r-l+1这个区间长度可能不是2的整数次幂,但是可以有重叠的部分,并不影响。

    则可以得到:dp[i][j]=max(dp[i][j-1],dp[i+2j-1][j-1])(DP的状态转移方程)

    //dp初始条件
    for(int i=0;i<n;i++)
    dp[i][0]=a[i];
    //填表
    for(int j=1;(1<<j)<=N;j++)
        for(int i=0;i+(1<<j-1)<=N;i++)
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);

    此处注意内外层循环,这个填表过程相当于竖着填表。

    3.2查询(时间复杂度O(1))

    我们回到题目:对于长度为N的序列,询问区间[L,R]中的最值,假设这里我们需要的是最大值,毋庸置疑,rmq=dp[L][m],就是从L开始,长度为2m,r-l+1=2m解得m=log2(r-l+1)问题是前文中提到得l-r+1不一定是2的整数次幂.

    所以我们将其转换为求两个区间这两个区间为[l,l+2k-1][r-2k+1,r],一个确保了开头为l,另一个确保了结尾为r,得问题:rmq=max(dp[L][k],dp[r-2k+1][k]),这个2k可以是[l,r]之间重叠的部分,保证覆盖[l,r]之间所有的数。

    我们要维护的两个区间是[l,l+2k-1][r-2k+1,r],为了保证覆盖[l,r]之间所有的数就要满足:l+2k-1>=r-2k+1

    化简得:k>=log2(r-l+1)-1,所以k=log2(r-l+1)-1时,可以满足求得[l,r]之间得最值问题

    int k=log2(r-l+1)-1
    rmq=max(dp[l][k],dp[r-(1<<k)+1][k]);
  • 相关阅读:
    ASP.Net控件基础篇
    ASP.Net
    有关于静态
    重载
    继承和多态
    面向对象的封装
    .net webform 把word转为html
    lambda 表达式 比较时间大小
    js 根据名字获取cookie 的方法
    .net 常用的命名空间和类
  • 原文地址:https://www.cnblogs.com/code-fun/p/12499895.html
Copyright © 2011-2022 走看看