不想解释,so推荐一个更好的网站
http://blog.csdn.net/insistgogo/article/details/9929103
http://www.cnblogs.com/zyf0163/p/4782133.html
总结: 用处:快速求解一个给定区间内的最值
方法:ST算法分成两部分:离线预处理 (nlogn)和 在线查询(O(1))。虽然还可以使用线段树、树状链表等求解区间最值,但是ST算法要比它们更快,而且适用于在线查询。
(1)离线预处理:运用DP思想,用于求解区间最值,并保存到一个二维数组中。
状态转移方程是 F[i,j] = min(F[i,j - 1],F[i + 2^(j - 1),j - 1])
初始状态为:F[i,0] = A[i]
(2)在线查询:对给定区间进行分割,借助该二维数组求最值
在程序计算求解区间长度时,并没有那么麻烦,我们可以直接得到i,即等于直接对区间长度取以2为底的对数。这里,对于区间[3,11],其分解的区间长度为int(log(11 - 3 + 1)) = 3,这里log是以2为底的。
#include <iostream> #include <math.h> using namespace std; /*方程 F[i,j]:区间[i,i + 2^j - 1]的最小值,此时区间长度为2^j F[i,j] = min(F[i,j - 1],F[i + 2^(j - 1),j - 1]) F[i,0] = nArr[i];*/ int F[1000000][20];//待比较元素的个数最大为1百万 void SparseTable(int nArr[],int nLen) { //初始化 for (int i = 0;i < nLen;i++) { F[i][0] = nArr[i]; } //递推 int nLog = int(log(double(nLen))/log(2.0)); for (int j = 1;j <= nLog;j++) { for (int i = 0;i < nLen;i++) { if ((i + (1 << j) - 1) < nLen)//区间的端点不能超过数组最后一位的下标 { F[i][j] = min(F[i][j - 1],F[i + (1 << (j - 1))][j - 1]); } } } } int RMQ(int nArr[],int nLen,int nStart,int nEnd) { int nLog = (int)(log(double(nEnd - nStart + 1)/log(2.0))); return min(F[nStart][nLog],F[nEnd - (1 << nLog) + 1][nLog]); } int main() { int nArr[6] = {5,4,6,10,1,12}; SparseTable(nArr,6); cout<<RMQ(nArr,6,0,5)<<endl; cout<<RMQ(nArr,6,1,3)<<endl; cout<<RMQ(nArr,6,2,5)<<endl; cout<<RMQ(nArr,6,2,2)<<endl; system("pause"); return 1; }