- Sum of Subarray Ranges
You are given an integer array nums. The range of a subarray of nums is the difference between the largest and smallest element in the subarray.
Return the sum of all subarray ranges of nums.
A subarray is a contiguous non-empty sequence of elements within an array.
1.直接解法
对于子序列nums[i,j],最大值等于max(nums[i,j-1], nums[j]),同理,最小值等于min(nums[i,j-1], nums[j])。双重循环遍历所有子序列,先枚举子数组的左边界,再枚举子数组的右边界,求最大值和最小值。
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long int sum=0;
for(int i=0;i<nums.size();i++){
int maxv=nums[i];
int minv=nums[i];
for(int j=i+1;j<nums.size();j++){
maxv=max(maxv,nums[j]);
minv=min(minv,nums[j]);
sum+=maxv-minv;
}
}
return sum;
}
};
2.单调栈解法
(1)对于nums[i],左边最近的比它小的元素下标为j,右边最近的比它小的元素为k,以[j+1,i]之间元素为左边界,以[i,k-1]之间元素为右边界,则共有(k-i) * (i-j)种子序列,这些子序列的最小元素都是nums[i]。若是左边没有比它更小的元素,则从0开始到i都可以作为左边界,共有(i+1)种可能,可以令j=-1;若是右边没有比它更小的元素,则从i到n-1都可以作为右边界,共有(n-i)种可能,可以令k=n
(2)左边最近的比它大的元素下标为j,右边最近的比它大的元素为k,以[j+1,i]之间元素为左边界,以[i,k-1]之间元素为右边界,则共有(k-i)*(i-j)种子序列,这些子序列的最大元素都是nums[i]。
(3)求所有子序列的范围和,即所有子序列的最大值之和减去所有子序列的最小值之和。
(4)注意:
①出现相同元素时,应该规定右边(或左边)的更大
②计算乘积的时候,数值可能会比较大,应该强制类型转换
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n=nums.size();
vector<int>minLeft(n),minRight(n),maxLeft(n),maxRight(n);
stack<int>minStack,maxStack;
for(int i=0;i<n;i++){
while(!minStack.empty() && nums[minStack.top()]>nums[i]){
minStack.pop();
}
minLeft[i]=minStack.empty()?-1:minStack.top();
minStack.push(i);
while(!maxStack.empty()&&nums[maxStack.top()]<=nums[i]){
maxStack.pop();
}
maxLeft[i]=maxStack.empty()?-1:maxStack.top();
maxStack.push(i);
}
minStack=stack<int>();
maxStack=stack<int>();
for(int i=n-1;i>=0;i--){
while(!minStack.empty() && nums[minStack.top()]>=nums[i]){
minStack.pop();
}
minRight[i]=minStack.empty()?n:minStack.top();
minStack.push(i);
while(!maxStack.empty()&&nums[maxStack.top()]<nums[i]){
maxStack.pop();
}
maxRight[i]=maxStack.empty()?n:maxStack.top();
maxStack.push(i);
}
long long sumMax=0,sumMin=0;
for(int i=0;i<n;i++){
sumMax+=(long long)nums[i]*(maxRight[i]-i)*(i-maxLeft[i]);
sumMin+=(long long)nums[i]*(minRight[i]-i)*(i-minLeft[i]);
}
return sumMax-sumMin;
}
};