子数组范围和

题目
给你一个整数数组 nums 。nums 中,子数组的 范围 是子数组中最大元素和最小元素的差值。

返回 nums 中 所有 子数组范围的 和 。

子数组是数组中一个连续 非空 的元素序列。

链接:https://leetcode-cn.com/problems/sum-of-subarray-ranges

思路
方法一:朴素思路,二重循环枚举每个子数组
方法二:单调栈
题目转化
问题转成求解所有区间的最大值的和减去所有区间的最小值的和
进一步的考虑每一个元素作为区间的最大值的区间个数,作为区间的最小值的区间个数
使用简单的例子去理解
防止有相等元素,所以从左向右使用>=和从右向左<
单调栈直观的理解是能处理的元素,就处理,不能处理的元素存入栈中,稍后处理

代码

class Solution {
public:
    long long subArrayRanges(vector<int>& nums) {

        int n=nums.size();
        vector<int> left_s(n,0);    // 记录索引
        vector<int> right_s(n,0);
        vector<int> left_l(n,0);
        vector<int> right_l(n,0);

        stack<int> s;         // 记录索引
        s.push(-1);

        // 单调递增栈,从左向右
        for(int i=0;i<n;i++){

            while(s.top()!=-1 && nums[s.top()]>=nums[i])  // 栈中的元素始终有序
            s.pop();          // 不满足条件,出栈

            left_s[i]=s.top();
            s.push(i);            // 满足条件,入栈
        }

        s.empty();

        // 单调递增栈,从右向左
        s.push(n);
        for(int i=n-1;i>=0;i--){

            while(s.top() != n && nums[s.top()]>nums[i])
            s.pop();

            right_s[i]=s.top();
            s.push(i);
        }

        s.empty();

        // 单调递减栈,从左向右
        s.push(-1);

        for(int i=0;i<n;i++){

            while(s.top()!=-1 && nums[s.top()]<=nums[i])
            s.pop();

            left_l[i]=s.top();
            s.push(i);
        }

        s.empty();

        // 单调递减栈,从右向左
        s.push(n);

        for(int i=n-1;i>=0;i--){
            while(s.top() !=n && nums[s.top()]<nums[i])
            s.pop();

            right_l[i]=s.top();
            s.push(i);
        }

        s.empty();

        long long ans=0;

        for(int i=0;i<n;i++){

            ans += 1L*nums[i]*(right_l[i]-i)*(i-left_l[i]);
            ans -= 1L*nums[i]*(right_s[i]-i)*(i-left_s[i]);
        }

        return ans;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值