RMQ(范围内最小值)
问题描述:给出一个n个元素的数组A1,A2,A3,....An,给你L,R让你计算min{AL,AL+1,AL+2......AR}
接下来我们就要进入正题了,Tarjan的Space-Table算法,这个算法基于DP的思想,算法复杂度O(nlogn)
我们采用动态规划的思想来处理范围最小值问题
dp[i][j]表示从i开始,长度为2的j次幂的一段元素的最小值,
状态转移方程为
dp[i][j] = min(dp[i][j-1],dp[i+2^(j-1)][j-1]);
这个转移方程有一个最重要的初始化
for 1 to n
dp[i][0] = A[i];
我们发现以i开始2^0都是A[i];
我们递推几个例子
i = 1 j = 1
dp[1][1] = min(dp[1][0],dp[1+2^(1-1)][0]) ->dp[1][1] = min(A[1],A[2]) A[1],A[2]
i = 2 j = 1
dp[2][1] = min(dp[2][0],dp[2+2^(1-1)][0]) ->dp[2][1] = min(A[2],A[3]) A[2],A[3]
.
.
i = n j = 1
dp[n][1] = min(dp[n][0],dp[n+2^(1-1)][0]) ->dp[n][1] = min(A[n],A[n+1]) A[n],A[n+1]
i = 1 j = 2
dp[1][2] = min(dp[1][1],dp[1+2^(2-1)][1])->dp[1][2] = min(dp[1][1],dp[3][1])
i = 2 j = 2
dp[2][2] = min(dp[2][1],dp[2+2^(2-1)][1])->dp[2][2] = min(dp[2][1],dp[4][1])
.
.
下面就不推了····你会发现很巧妙的把任意区间的最小值都求出来了·····DP好厉害····
我们的程序也就出来了
int RMQ_init()}
我们根据递推也会发现为什么先从j循环了吧。。
然后是查询··
我们应该找到个K,让K满足2^k<=R-L+1,也就是以L开头,以R结尾的2^K的区间
int RMQ(int L,int R)
{
int k = 0;
while(1<<(k+1)<=R-L+1) k++;
return min(dp[L][k],dp[R-(1<<k)+1][k]);
}
代码其实非常简单,今天又看了一遍,有了更深的理解,书还是要多看的哦