2104. Sum of Subarray Ranges

  1. 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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值