leetcode 907. Sum of Subarray Minimums

leetcode 907. Sum of Subarray Minimums

题目大意

  • 将数组划分为若干个子数组(子数组必须是连续的几个数),每个子数组都取数组里面最小值。求这些最小值的和

###思路

  • 首先应该先明确这题的解题思路一定是算每个数的贡献次数,因为每个数至少有一次机会成为最小值(只有它本身的时候)
  • 算一个数的贡献次数,其实就是看它在多大的范围内是这范围内的最小值,举个简单例子,3 1 2 4 这4个数,如果我知道了 1 这个数,它能成为最小值的范围是从0 到 3(因为下标从0开始),那么你如何计算它的贡献次数?? 其实非常简单,1 这个数,可以和左边的3组合,也可以分别和右边的 2,(2,4)组合,所以贡献次数就是(左边个数+1)(右边个数+1) 23 =6次
  • 知道了如何计算,下面的问题就是求出一个数的影响范围就行。思路很简单,单调栈就行。不知道单调栈的可以百度。
  • 注意一个细节,那就是重复元素的问题,比如 1 1 1 1 这4个数,你的范围给如何确定? 你可以规定一个方向,向左不能有重复元素,向右可以取等就行。这主要是涉及单调栈的知识,这里不再细讲。
    ###代码
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
typedef long long ll;
const int mod=1e9+7;
    int sumSubarrayMins(vector<int>& A) {
        int f[30005],g[30005];
        int n= A.size();
        stack<int> sta;
        memset(f,-1,sizeof(f));
        for(int i=0;i<n;i++)
        {
            g[i]=n;
        }
        for(int i=0;i<n;i++)
        {
            while(sta.empty()==0&&A[sta.top()]>A[i])
            {
                sta.pop();
            }
            if(sta.empty()==0)
            {
                f[i]=sta.top();
            }
            sta.push(i);
        }
        while(sta.empty()==0) sta.pop();
        for(int i=n-1;i>=0;i--)
        {
            while(sta.empty()==0&&A[sta.top()]>=A[i])
            {
                sta.pop();
            }
            if(sta.empty()==0)
            {
                g[i]=sta.top();
            }
            sta.push(i);
        }
        ll ans=0;
        for(int i=0;i<n;i++)
        {
            ans=(ans+(i-f[i])*(g[i]-i)*A[i])%mod;
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/85853954