LeetCode 2104. 子数组范围和
区间最值RMQ
const int N = 1010, M = 11;
class Solution {
public:
int f[N][M], g[N][M];//i-j最大值和最小值
void init(vector<int>& nums)
{
int n = nums.size();
for(int j = 0; j < M; j ++)
for(int i = 0; i + (1 << j) - 1 < n; i ++)
{
if(!j) f[i][j] = nums[i];
else f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
for(int j = 0; j < M; j ++)
for(int i = 0; i + (1 << j) - 1 < n; i ++)
{
if(!j) g[i][j] = nums[i];
else g[i][j] = min(g[i][j - 1], g[i + (1 << (j - 1))][j - 1]);
}
}
int query(int l, int r)
{
int len = r - l + 1;
int k = log(len) / log(2);
return max(f[l][k], f[r - (1 << k) + 1][k]) - min(g[l][k], g[r - (1 << k) + 1][k]);
}
long long subArrayRanges(vector<int>& nums) {
init(nums);
long long res = 0;
int n = nums.size();
for(int i = 0; i < n; i ++)
for(int j = i + 1; j < n; j ++)
res += query(i, j);
return res;
}
};
区间DP
const int N = 1010;
class Solution {
public:
int f[N][N][2];//i-j区间最大值1和最小值0
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
for(int i = 0; i < n; i ++) f[i][i][1] = f[i][i][0] = nums[i];
for(int len = 2; len <= n; len ++)
for(int l = 0; l + len - 1 < n; l ++)
{
int r = l + len -1;
f[l][r][0] = min(f[l][r - 1][0], nums[r]);
f[l][r][1] = max(f[l][r - 1][1], nums[r]);
}
long long res = 0;
for(int i = 0; i < n; i ++)
for(int j = i + 1; j < n; j ++)
{
res += f[i][j][1] - f[i][j][0];
}
return res;
}
};
滚动优化
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
long long res = 0;
for(int i = 0; i < n; i++)
{
int minv = nums[i], maxv = nums[i];
for(int j = i + 1; j < n; j ++)
{
minv = min(minv, nums[j]);
maxv = max(maxv, nums[j]);
res += maxv - minv;
}
}
return res;
}
};