方法一:递推 O(n^2) 比较容易想到
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
long long ans = 0;
for (int i = 0; i < n; ++i) {
int _max = nums[i];
int _min = nums[i];
for (int j = i + 1; j < n; ++j) {
_max = max(_max, nums[j]);
_min = min(_min, nums[j]);
ans += ((long long)_max - _min);
}
}
return ans;
}
};
方法二:单调栈 O(n)
具体细节:考虑贡献。
左边第一个小的下标j,右边k,则贡献的区间个数为:(i-j)*(k-i),这是最小值
最大值同理
难点:!!!
为了使得最大最小值统一(比如1 3 3,此时如果只按照值比较的话,” 3 3“这个区间会重复计算!!!),规定相等元素按照下标进行比较,所以:
左边小的: <=
右边小的: <
左边大的:>
右边大的:>=
,即用单调栈分别找以上4个值。
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
vector<int> l_smaller(n, -1), r_smaller(n, n), l_bigger(n, -1), r_bigger(n, n);
vector<int> stk(n);
int top = -1;
for (int i = 0; i < n; ++i) {
while (top != -1 && nums[stk[top]] > nums[i]) {
r_smaller[stk[top]] = i;
--top;
}
if (top != -1) l_smaller[i] = stk[top];
stk[++top] = i;
}
top = -1;
for (int i = n - 1; i >= 0; --i) {
while (top != -1 && nums[stk[top]] < nums[i]) {
l_bigger[stk[top]] = i;
--top;
}
if (top != -1) r_bigger[i] = stk[top];
stk[++top] = i;
}
long long ans = 0;
for (int i = 0; i < n; ++i) {
ans -= (nums[i]) * (long long)(i - l_smaller[i]) * (r_smaller[i] - i);
//区间乘以元素最大值为12次方,int会越界,所以要用long long强转一下
ans += (nums[i]) * (long long)(i - l_bigger[i]) * (r_bigger[i] - i);
}
return ans;
}
};