NC386 子数组的最小值之和

子数组的最小值之和

https://www.nowcoder.com/practice/a7401d0dd4ec4071a31fd434e150bcc2?tpId=196&tqId=40517&rp=1&ru=/exam/oj&qru=/exam/oj&sourceUrl=%2Fexam%2Foj&difficulty=undefined&judgeStatus=undefined&tags=581&title=

思路: alt

class Solution {
public:
    int sumSubarr(vector<int>& nums) {
        int n=nums.size();
        long ans=0;
        //leftmin用于存每个元素左边第一个小于本身的元素的位置
        //rightmin用于存每个元素右边第一个小于等于本身的元素的位置
        vector<int>leftmin(n,-1);
        vector<int>rightmin(n,n);
        //进行取余10^9+7
        const int M=1000000007;
        //用单调栈维护
        stack<int>stack1;
        //正向遍历找到每个元素左边第一个小于等于本身的元素的位置,
        //但是记录的时候就反着记:记每个元素右边第一个小于等于本身的元素的位置
        for(int i=0;i<n;i++){
            while(!stack1.empty()&&nums[stack1.top()]>nums[i]){
                rightmin[stack1.top()]=i;
                stack1.pop();
            }
            stack1.push(i);
        }
        //调用无参构造函数将栈清空
        stack1=stack<int>();
        //反向遍历找到右边第一个小于本身的元素的位置
        for(int i=n-1;i>=0;i--){
            while(!stack1.empty()&&nums[stack1.top()]>=nums[i]){
                leftmin[stack1.top()]=i;
                stack1.pop();
            }
            stack1.push(i);
        }
        //推导出来的公式:以nums[i]为最小元素的区间个数时left[i]*right[i]
        //所以以nums[i]为最小元素之和是:nums[i]*left[i]*right[i]
        for(int i=0;i<n;i++){
            int l=leftmin[i];
            int r=rightmin[i];
            ans+=(long)((r-i)*(i-l)%M)*nums[i]%M;
        }
        return ans%M;
    }
};
全部评论

相关推荐

缒梦&独舞:这家公司是这样的,去年给我实习offer了,不过也是面着玩儿的,他周六还要去做公益志愿活动
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务