ST(Spare Table稀疏表)算法采用了倍增思想,在O(nlogn)时间构造一个二维表,可以在O(1)时间在线查询[l,r]区间的最值,有效解决在校RMQ(Range Minimum/Maximum Query,区间最值查询)问题。
如何实现呢?
设F[i,j]表示[i,2j -1]区间的最值,区间长度为2j 。
根据倍增思想,长度为2j 的区间可分成两个长度为2j-1 的子区间的最值即可。递推公式:F[i,j]=max(F[i,j-1],F[i+2j-1 ,j-1])。
通过上面的讲解其实就是动态规划思想。
1、ST创建
若F[i,j]表示[i,i+2j -1]区间的最值,区间长度为2j ,则i和j的取值范围是多少呢?
若数组的长度为n,最大区间长度2k ≤n<2k+1 ,则k=log2 n 向下取整,比如n=8时k=3,n=10时k=3.
在程序中,k=log2(n),也可用通用表达方式k=log(n)/log(2),log()表示以e为底的自然对数。
算法代码:
void ST_create(){
for(int i=1;i<=n;i++)
F[i][0]=a[i];//表示[i,i]区间的最值,区间长度为2^0
int k=log2(n);
for(int j=1;j<=k;j++)
for(int i=1;i<=n-(1<<j)+1;i++)//n-2^j+1
F[i][j]=max(F[i][j-1],F[i+(1<<(j-1))][j-1]);
//j用来控制区间大小
}
例如有10个元素a[1…10]={5,3,7,2,12,1,6,4,8,15},其查询最值的ST如下图所示。
F[i,j]表示[i,i+2j-1] 区间的最值,区间长度为2j
2、ST查询
若查询[l,r]区间的最值,则首先计算k的值,和前面的计算方法相同,区间长度为r-l+1,2k ≤r-l+1<2k+1 ,因此k=log2(r-l+1)。
若查询区间长度为大于等于2k且小于2k+1 ,则根据倍增思想,可以将查询区间分为两个查询区间,取两个区间的最值即可。两个区间分别从l向后的2k 个数及从r向前2k 个数。
算法代码:
int ST_query(int l,int r)
{
int k=lng2(r-l+1);
return max(F[l][k],F[r-(1<<2)+1][k]);
}