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;
}
};