907 子数组的最小值之和
给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
输入:[3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。
详细解答:
这道题看起来很简单,便利整个数组记录最小值似乎就可以完成,我第一次就是这样做的,结果就是超时,明显就是不能暴力解决问题,要用巧,此题怎么用巧呢,请耐心看下面详细分解。
我们假设 数组A={3,1,2,4,5,0,7,8};
我们用栈记录记录上次访问到最小值的下标。其实不用栈也行,只要记住最小值的下标就行;
假如上次遍历到的最小值为1,下标是1,
当我们遍历到0时,1的右边数组{1,2,4,5},{1,2,4},{1,2},{1}这些子数组的最小值都是0,总数为0的下标-1的下标=5-1=4
再加上{3,1},(上上一次最小值3的下标与上一次最小值1的下标之间的距离就是左边的次数)
total=left×right;
为了遍历到每一个点,我们必须在数组后添加一个0;
因此我们的解题代码如下;
class Solution {
public:
int sumSubarrayMins(vector<int>& A) {
stack<int> s;
int size = A.size(), sum = 0, mod = 1e9 +7;
A.push_back(0);
for(int i = 0; i <= size; i++){
while(!s.empty() && A[i] < A[s.top()]){
int j = s.top();
s.pop();
int left = j - (s.empty() ? -1 : s.top());
sum = (sum + left * (i - j) * A[j]) % mod;
}
s.push(i);
}
return sum;
}
};