1.RMQ问题
RMQ (Range Minimum/Maximum Query):对于长度为n的数组A,回答若干询问RMQ(A,i,j)(i,j<=n-1),返回数组A中下标在i,j范围内的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。最简单的方法,就是遍历数组直接搜索,但是这种方式时间复杂度是O(n)。对于数组长度较大,性能要求高的场景不适用。
2.ST(Sparse Table)算法
ST算法是一种更加高效的算法,以O(nlogn)的预处理代价,换取O(1)的查询时性能。现在我们来看下ST算法的思路和求解过程。假设有一个长度n=10的数组a,各个数组元素a[0],a[1]……a[9]的值分别是3 ,2, 4, 5 ,6, 8 ,1,2, 9, 7。我们以求最大值为例,令0 <= i <= j <= n-1,那么RMQ(a,i,j)就是:找出a[i],a[i+1]....a[j]这些元素中的最大值。令f[i,j]代表从第i个数起连续2^j个数中的最大值。
显然f[i,0]的值是确定的,就是第i个数自己。即f[i,0] = a[i],这就是动态规划DP的初始条件值。
现在我们来看下动态规划的状态转移方程,有了初始值和动态转移方程,就能够用动态规划算法解决问题。
为了求f[i,j],我们把f[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。显然f[i , j] = max(f[i , j-1],f[ i + 2^(j-1), j-1])。
目前为止,已经有了DP的初始化条件和状态转移方程。接下来我们来看如何利用f[i,j]来RMQ(a, i, j)。
取k=[log2(j-i+1)],则有:RMQ(a, i, j) = max{f[i,k], f[j-2^k+1,k]}。
举例说明,如果要求区间[2,8]的最大值,总共2到8是7个元素,所以k=2,那么就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由f[2,2]和f[5,2]得到。
现在我们看下k的值是如何得出的。假设拆分成的2个子区间,每个子区间都有2^(k-1)个元素。则2个子区间分别为:
[i, 2^(k-1) + i -1]和[j - 2^(k-1) + 1,j]。显然必须要满足2个子区间能够完全覆盖[i,j],即(2^(k-1) + i -1) + 1 >= (j - 2^(k-1) +1)
进而可以推导出 2^k >= (j - i + 1)。这样的话,我们取满足条件的K最小值就可以了。为什么要取最小值呢?是为了保证2个子区间长度尽可能的短。