(一)首先是预处理,用动态规划(DP)解决。
设A[i]是要求区间最值的数列,F[i, j]表示从第i个数起连续2^j个数中的最大值。(DP的状态)
如数列 2,4,5,6,8,7,9,10,1,3
F[0,1]表示从下标0开始,2个元素的最大值,则F[0,1]=max(2,4)=4,F[1,2]=max(4,5,6,8)=8,而F[0,0]=max(2)=2,F[1,0]=4。因此F[i,0]就等于A[i]。(DP的初始值)
这样,DP的状态、初值都已经有了,剩下的就是状态转移方程。
把F[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从 i 到i + 2 ^ (j - 1) - 1为一段,i + 2 ^ (j - 1)到i + 2 ^ j - 1为一段(长度都为2 ^ (j - 1))。用上例说明,当i=2,j=2时就是5,6和 8,7这两段。F[i,j]就是这两段各自最大值中的最大值。于是我们得到了状态转移方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])。预处理代码:
- #define max(a,b) a>b?a:b
- #define min(a,b) a<b?a:b
- void rmq()
- { int temp=(int)(log((double)n)/log(2.0));
- for(int i=0;i<n;i++)
- DP[i][0]=a[i];
- for(int j=1;j<=temp;j++)
- for(int i=0;i<n;i++)
- if(i+(1<<j)<=n) DP[i][j]=max(DP[i][j-1],DP[i+(1<<(j-1))][j-1]);
- }
- DP二维数组结果如图所示
-
- {注:DP是保存区间最值的二维数组,下标[i][j]代表某区间}
- 通过DP这个数组,在此数列中,我们可以查询(i,j){i>=0,j<=9)任意一个区间的最大值。时间复杂度为O(1)。这就是sT,具体如下。
- (二)ST(Sparse Table)
-
举个例:如果我们要查询(2,7)这个区间的最大值(即:从下标2开始,到下标7这其间的数据哪个最大),则取 K=log2(j-i+1)=log2(7-2+1)=2 {j-i+1是区间的长度},即区间元素个数。k将这个区间分成了两个长度为2^k的块。查最大值就是找这两个区间的最大值,即:RMQ(i,j)=max(F[i,k],F[j-2^k+1,k]);此例
-
RMQ(2,7)=max(F[2,2],F[4,2])=max(8,10)=10。F[2,2]对应的DP[2][2],F[4,2]对应的DP[4][2]。所以预处理后,查询某区间的值时间复杂度为O(1)
-
- int Maxmum(int i,int j)
- { int k=(int)(log((double)j-i+1)/log(2.0));
- return max(DP[i][k],DP[j-(1<<k)+1][k]);
- }
-
总结:这就是RMQ
- 自己的理解哈,仅供参考
-