题目
思路一 枚举
枚举所有起点和终点,计算最大值到最小值的差,并添加到结果中。
代码一
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long ans = 0;
int n = nums.size();
for(int i = 0; i < n; i++){
int minn = nums[i], maxx = nums[i];
for(int j = i + 1; j < n; j++){
minn = min(minn, nums[j]);
maxx = max(maxx, nums[j]);
ans += maxx - minn;
}
}
return ans;
}
};
思路二 单调栈
假设有m个区间,最终的表达式为m个等式max-min之和。用min数组和max数组存储每个数作为区间最小值和最大值的次数k1和k2,那么结果就是(k2-k1)*nums[i]为nums[i]对于最终答案的贡献。统计每个nums[i]称为区间最值的次数:例如找到nums[i]作为区间最大值的次数,找到nums[i]左右最近一个不满足小于等于nums[i]的位置,记为p和q。此时区间左端点共有i-p个选择,右端点共有q-i个选择,那么区间个数为(i-p)*(q-i)个。
代码二
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
long long ans = 0;
vector<long> minn = getCnt(nums,true), maxx = getCnt(nums,false);
for(int i = 0; i < n; i++)
ans += (maxx[i] - minn[i]) * nums[i];
return ans;
}
vector<long> getCnt(vector<int>& nums, bool isMin){
int n = nums.size();
vector<int> a(n), b(n);
stack<int> s;
for(int i = 0; i < n; i++){
while(!s.empty() && (isMin ? nums[i] <= nums[s.top()] : nums[i] >= nums[s.top()]))
s.pop();
a[i] = s.empty() ? -1 : s.top();
s.push(i);
}
while(!s.empty()) s.pop();
for(int i = n - 1; i >= 0; i--){
while(!s.empty() && (isMin ? nums[i] < nums[s.top()] : nums[i] > nums[s.top()]))
s.pop();
b[i] = s.empty() ? n : s.top();
s.push(i);
}
vector<long> ans(n);
for(int i = 0; i < n; i++)
ans[i] = (i - a[i]) * (b[i] - i);
return ans;
}
};