• RMQ问题与ST算法


    RMQ(Range Minimum/Maximum Query)问题是求区间最值问题。

    对于长度为 n 的数组 A,进行若干次查询,对于区间 [L,R] 返回数组A中下标在 [L,R] 中的最小(大)值。

    可以用线段树来解决这个问题,预处理的复杂度是 O(nlogn),查询的复杂度是 O(logn)。

    更好的解法是ST算法。Sparse_Table算法,即稀疏表算法,这个方法可以在 O(nlogn) 的预处理后达到 O(1) 的查询代价。

    这个算法非常容易实现。

    定义 F[ i, k ] 表示从 i 开始的,长度为 2^k 的区间内元素的最小值。

    当 k = 0 时,F[ i, 0 ] 的值显然就是A[ i ] 的值。

    而 k > 0 时,对于从 i 开始的长度为 2^k 的区间,它的最小值显然是从 i 开始的长度为 2^(k-1) 的区间中的最小值与从 i+2^(k-1)开始的长度为 2^(k-1) 的区间中的最小值中更小的那一个。

    则有递推公式 F[ i, k ] = min{ F[ i, k-1 ], F[ i+2^(k-1), k-1] }

    由于 2^k<=n,因此 F 数组中的元素个数不会超过 nlogn,而每个元素都可以在O(1)的时间内计算出,因此总时间为O(nlogn)。

    1 int F[maxn][20];
    2 //元素从1编号到n
    3 void RMQ_init(int A[],int n){
    4     for (int i=1;i<=n;i++) F[i][0]=A[i];
    5     for (int k=1;(1<<k)<=n;k++)
    6         for (int i=1;i+(1<<k)-1<=n;i++)
    7             F[i][k]=min(F[i][k-1],F[i+(1<<(k-1))][k-1]);
    8 }
    RMQ的预处理

    对于查询操作 [L,R],定义 k 为满足 2^k<=R-L+1 的最大整数。

    则以L开头的长度为 2^k 的区间与以R结尾的长度为 2^k 的区间,能够完整的覆盖区间 [L,R]。

    因此这两个区间的最小值中更小的那一个就是所查询的区间 [L,R] 的最小值。

    1 int RMQ(int L,int R){
    2     int k=0;
    3     while ((1<<(k+1))<=R-L+1) k++;
    4     return min(d[L][k],d[R-(1<<k)+1][k]);
    5 }
    RMQ查询

    ST 算法也可以求出最值所在的下标,只要将 F 数组中储存的值变为数组 A 的下标即可。

  • 相关阅读:
    PAT:循环-12. 打印九九口诀表(15) AC
    PAT:循环-07. 爬动的蠕虫(15) 错两个
    PAT:循环-01. 求整数段和(15) AC
    PAT:分支-16. 计算分段函数(10) AC
    PAT:分支-10. 计算个人所得税(10) AC
    PAT:分支-08. 高速公路超速处罚(15) AC
    UIToolBar
    iOS 代码实现获得应用的版本号(Version/Build)
    IOS开发之 ---- iOS8中提示框的使用UIAlertController(UIAlertView和UIActionSheet二合一)
    IOS开发中的CGFloat、CGPoint、CGSize和CGRect
  • 原文地址:https://www.cnblogs.com/zinthos/p/3899582.html
Copyright © 2020-2023  润新知