RMQ算法
RMQ (Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。
通常来说RMQ算法的实现有两种方法
1、线段树实现。这里不讲,可以参考http://www.cnblogs.com/ISGuXing/articles/7215486.html
时间复杂度大概是O(n)-O(qlogn)
2、第二种方法就是ST算法
预处理时间复杂度为O(nlogn) 查询的时间为O(1);
适合用于比较多的数据的查询。
该算法的核心其实就是动态规划。(ps:再一次说明动态规划思想的重要性!)
在这篇随笔中笔者就不讲ST算法具体实现是怎么样的,贴上一个比较好的文章http://blog.csdn.net/niushuai666/article/details/6624672
在这篇随笔主要讲数组F[ n] [20]含义是什么,为什么这样做。
F[i, j]表示从第i个数起连续2^j个数中的最大值。(DP的状态)
那么当j=0的时候也就是区间只有i 它本身的时候最值肯定是其本身。
这是初始化。
那么状态转移方程就能出来了F[i, j] =max( F[ i, j-1] ,F[i+(1<<(j-1)) , j-1] )
想一想将一个区间二分是不是这个样子。
既然这也出来了,那么查询就很清晰了
假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂(可以重复,比如查询5,6,7,8,9,我们可以查询5678和6789)。
因为这个区间的长度为j - i + 1,所以我们可以取k=log2( j - i + 1),则有:RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}。
举例说明,要求区间[2,8]的最大值,k = log2(8 - 2 + 1)= 2,即求max(F[2, 2],F[8 - 2 ^ 2 + 1, 2]) = max(F[2, 2],F[5, 2]);
在这里我们也需要注意一个地方,就是<<运算符和+-运算符的优先级。
比如这个表达式:5 - 1 << 2是多少?
答案是:4 * 2 * 2 = 16。所以我们要写成5 - (1 << 2)才是5-1 * 2 * 2 = 1。
ps:部分内容转自上面的那份博客。