题目:
给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。
由于答案可能很大,因此 返回答案模 10^9 + 7 。
思路:
如果枚举所有子数组,再逐个求最小值,显然是行不通的。应该逆向思考这个问题,即求最小值为某个值的区间个数,由于最小值一定在arr中产生,可以遍历每一个值,求出以它为最小值的区间数目。
如何界定呢?方法是找到左右两边最近的更小值的位置,这样,(left,now]都可以作为起点,[now,right)的都可以作为终点,一乘就可以了。
代码:
class Solution {
public:
int sumSubarrayMins(vector<int>& arr) {
arr.push_back(INT_MIN);//为了确保全部计算,人为添加一个下界
vector<int> prePos(arr.size());//维护前一个更小元素的位置,在入栈时得出
stack<int> stk;//单调递减栈,保存下标
long long ans=0,mod=1e9+7;
for(int i=0;i<arr.size();++i)
{
while(!stk.empty()&&arr[stk.top()]>=arr[i])//出栈并进行计算
{
int now=stk.top();
ans=(ans+1LL*(now-prePos[now])*(i-now)*arr[now])%mod;
stk.pop();
}
prePos[i]=stk.empty()?-1:stk.top();//保存前一个更小元素的位置
stk.push(i);
}
return ans;
}
};