1. 程式人生 > >leetcode 907. Sum of Subarray Minimums

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) 2
    3 =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;
    }
};