题目
- 给定一个数组,求数组某一个范围的最大值
- 通过下面的RQM结构,生成dp表的代价为 O(N*logN),查询的代价为 O(1)
- dp[i][j] 表示,从 i 位置开始(包括i位置)的 2^j 个数的最大值
- i从下标1开始,求下标1开始的 2^0、2^1、2^3、...不超过数组长度范围的最大值
- 然后i从下标2开始,求下标2开始的 2^0、2^1、2^3、...不超过数组长度范围的最大值
- 当 j 为 0时,每个位置开始的1个数的最大值也就是元素自身
- 当 j >0 时,假设j=3,i=10,表示10位置开始的 2^3 个数的最大值dp[10][3],就等价于dp[10][2]10位置开始的4个数的最大值,dp[14][2],14位置开始的4个数的最大值 相比,最大的那一个
- 因为 dp 表从上往下填 dp[i][j]=Math.max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]),所以下面的都能从上面已填写的信息得出答案
- 当查找[left,right]范围内的最大值时,为了避免长度奇偶的影响,将范围拆分成两个范围分别求解答案再比较,范围长度为 len ,小于等于len的2的最大指数为k,则先求前2^k个数的最大值,然后求right往前推2^k这个范围的最大值,再比较得出答案

class RMQ {
constructor(arr) {
this.len = arr.length;
const k = this.getPower2(this.len);
const dp = Array(len + 1).fill(0);
for (let i = 0; i < dp.length; i++) {
dp[i] - Array(k + 1).fill(0);
}
this.dp = dp;
this.setRMQ(arr);
}
setRMQ(arr) {
for (let i = 1; i <= this.len; i++) {
dp[i][0] = arr[i - 1];
}
for (let j = 1; 1 << j <= this.len; j++) {
for (let i = 1; i + (1 << j) - 1 <= this.len; i++) {
dp[i][j] = Math.max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
}
}
getPower2(len) {
let res = 0;
while (1 << res <= len) {
res++;
}
return res - 1;
}
getMax(left, right) {
const k = this.getPower2(right - left + 1);
return Math.max(this.dp[left][k], this.dp[right - (1 << k) + 1][k]);
}
}