Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A.

Since the answer may be large, return the answer modulo 10^9 + 7.

Example 1:

Input: [3,1,2,4]
Output: 17
Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4].
Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1.  Sum is 17.

Note:

  1. 1 <= A.length <= 30000
  2. 1 <= A[i] <= 30000

Approach #1: Monotone Stack. [Java]

class Solution {
public int sumSubarrayMins(int[] A) {
int n = A.length;
Stack<int[]> in_stk_p = new Stack<>(), in_stk_n = new Stack<>();
// left is for the distance to previous less element
// right is for the distance to next less element.
int[] left = new int[n], right = new int[n];
for (int i = 0; i < n; ++i) left[i] = i + 1;
for (int i = 0; i < n; ++i) right[i] = n - i; for (int i = 0; i < n; ++i) {
while (!in_stk_p.isEmpty() && in_stk_p.peek()[0] > A[i]) in_stk_p.pop();
left[i] = in_stk_p.isEmpty() ? i + 1 : i - in_stk_p.peek()[1];
in_stk_p.push(new int[] {A[i], i}); while (!in_stk_n.isEmpty() && in_stk_n.peek()[0] > A[i]) {
int[] x = in_stk_n.peek();
in_stk_n.pop();
right[x[1]] = i - x[1];
}
in_stk_n.push(new int[] {A[i], i});
} int res = 0, mod = (int)1e9 + 7;
for (int i = 0; i < n; ++i)
res = (res + A[i]*left[i]*right[i]) % mod; return res;
}
}

  

Analysis:

Before diving into the solution, we first introduce a very important stack type, which is called momotone stack.

What is monotonous increase stack?

Roughly spkeaking, the elements in the an monotonous increase stack keeps an increasing order.

The typical paradigm for monotonous increase stack:

for(int i = 0; i < A.size(); i++){
while(!in_stk.empty() && in_stk.top() > A[i]){
in_stk.pop();
}
in_stk.push(A[i]);
}.

  

What can monotonous increase stack do?

(1) find the previous less element of each element in a vector with O(n) time:

What is the previous less element of an element?

For example:

[3, 7, 8, 4]

The previous less element of 7 is 3.

The previous less element of 8 is 7.

The previous less element of 4 is 3.

There are no previous less element for 3.

For simplicity of notation, we use abbreviation PLE to denote Previous Less Element.

C++ code (by slitghly modifying the paradigm):

Instead of directly pushing the element itself, here for simplicity, we push the incex.

We do some record when the index is pushed into the stack.

// previous_less[i] = j means A[j] is the previous less element of A[i].

// previous_less[i] = -1 means there is no previous less element of A[i].

vector<int> previous_less(A.size(), -1);
for(int i = 0; i < A.size(); i++){
while(!in_stk.empty() && A[in_stk.top()] > A[i]){
in_stk.pop();
}
previous_less[i] = in_stk.empty()? -1: in_stk.top();
in_stk.push(i);
}

  

(2) find the next less element of each element in a vector with O(n) time:

What is the next less element of an element?

For example:

[3, 7, 8, 4]

The next less element of 8 is 4.

The next less element of 7 is 4.

There is no next less element for 3 and 4.

For simplicity of notation, we use abbreviation NLE to denote Next Less Element.

C++ code (by slighly modifying the paradigm):

We do some record when the index is poped out from the stack.

// next_less[i] = j means A[j] is the next less element of A[i].

// next_less[i] = -1 mean there is no next less element of A[i].

vector<int> previous_less(A.size(), -1);
for(int i = 0; i < A.size(); i++){
while(!in_stk.empty() && A[in_stk.top()] > A[i]){
auto x = in_stk.top(); in_stk.pop();
next_less[x] = i;
}
in_stk.push(i);
}

  

How can the monotonous increase stack be applied to this problem?

For example:

Consider the element 3 in the following vector:

        [2, 9, 7, 8, 3, 4, 6, 1]

         |         |

    the previous less    the next less

      element of 3       element of 3

After finding both NLE and PLE of 3, we can determine the distance between 3 and 2(prevous less), and the distance between 3 and 1(next less). In this example, the distance is 4 and 3 respectively.

How many subarray with 3 being its minimum value?

The answer is 4 * 3.

How much the element 3 contributes to the final answer?

It is 3 * (3 * 4).

What is the final answer?

Denote  by left[i] the distance between element A[i] and its PLE.

Denote by right[i] the distance beween element A[i] and its NLE.

The final answer is:

sum(A[i] * left[i] * right[i])

Approach #2: Optimize [C++]

class Solution {
public:
int sumSubarrayMins(vector<int>& A) {
int res = 0, n = A.size(), mod = 1e9 + 7, j, k;
stack<int> s;
for (int i = 0; i <= n; ++i) {
while (!s.empty() && A[s.top()] > (i == n ? 0 : A[i])) {
j = s.top(), s.pop();
k = s.empty() ? -1 : s.top();
res = (res + A[j] * (i - j) * (j - k)) % mod;
}
s.push(i);
}
return res;
}
};

  

Analysis:

1. Here we record (A[i], i) in the stack. We can also only record index.

2. For left part and right part, the logic is same.

So for each, we used one stack and one pass.

This process can be optimized to one pass using one stack in total.

Reference:

https://leetcode.com/problems/sum-of-subarray-minimums/discuss/170750/C%2B%2BJavaPython-Stack-Solution

https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html

https://leetcode.com/problems/sum-of-subarray-minimums/discuss/178876/stack-solution-with-very-detailed-explanation-step-by-step

907. Sum of Subarray Minimums的更多相关文章

  1. [LeetCode] 907. Sum of Subarray Minimums 子数组最小值之和

    Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarra ...

  2. 【leetcode】907. Sum of Subarray Minimums

    题目如下: 解题思路:我的想法对于数组中任意一个元素,找出其左右两边最近的小于自己的元素.例如[1,3,2,4,5,1],元素2左边比自己小的元素是1,那么大于自己的区间就是[3],右边的区间就是[4 ...

  3. [Swift]LeetCode907. 子数组的最小值之和 | Sum of Subarray Minimums

    Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarra ...

  4. 子数组最小值的总和 Sum of Subarray Minimums

    2018-09-27 23:33:49 问题描述: 问题求解: 方法一.DP(MLE) 动态规划的想法应该是比较容易想到的解法了,因为非常的直观,但是本题的数据规模还是比较大的,如果直接使用动态规划, ...

  5. leetcode907 Sum of Subarray Minimums

    思路: 对于每个数字A[i],使用单调栈找到A[i]作为最小值的所有区间数量,相乘并累加结果.时间复杂度O(n). 实现: class Solution { public: int sumSubarr ...

  6. LC 918. Maximum Sum Circular Subarray

    Given a circular array C of integers represented by A, find the maximum possible sum of a non-empty ...

  7. 动态规划-Maximum Subarray-Maximum Sum Circular Subarray

    2020-02-18 20:57:58 一.Maximum Subarray 经典的动态规划问题. 问题描述: 问题求解: public int maxSubArray(int[] nums) { i ...

  8. [Swift]LeetCode918. 环形子数组的最大和 | Maximum Sum Circular Subarray

    Given a circular array C of integers represented by A, find the maximum possible sum of a non-empty ...

  9. Maximum Sum Circular Subarray LT918

    Given a circular array C of integers represented by A, find the maximum possible sum of a non-empty ...

随机推荐

  1. win7 一切软件都安装不上 解决 把他卸掉

    KB2962872   控制面板,添加删除程序,查看已更新

  2. Spring Boot集成Quartz注入Spring管理的类

    摘要: 在Spring Boot中使用Quartz时,在JOB中一般需要引用Spring管理的Bean,通过定义Job Factory实现自动注入. Spring有自己的Schedule定时任务,在S ...

  3. 2018.10.18 bzoj4105: [Thu Summer Camp 2015]平方运算(线段树)

    传送门 线段树妙题. 显然平方几次就会循环(打表证明不解释). 然后所有环长度的lcmlcmlcm不大于70. 因此维护一下当前区间中的节点是否全部在环上. 不是直接暴力到叶子节点修改. 否则整体打标 ...

  4. 2018.08.31 bzoj3566: [SHOI2014]概率充电器(概率dp+容斥原理)

    传送门 概率dp好题啊. 用f[i]" role="presentation" style="position: relative;">f[i] ...

  5. 2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)

    传送门 题目就是要求维护带权重心. 因此破题的关键点自然就是带权重心的性质. 这时发现直接找带权重心是O(n)的,考虑优化方案. 发现点分树的树高是logn级别的,并且对于以u为根的树,带权重心要么就 ...

  6. Django介绍(3)

    https://www.cnblogs.com/yuanchenqi/articles/5786089.html

  7. Django介绍(1)

    https://www.cnblogs.com/yuanchenqi/articles/6083427.html 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构, ...

  8. PHP中的mb_convert_encoding与iconv函数介绍

    php传输乱码 mb_convert_encoding这个函数是用来转换编码的.原来一直对程序编码这一概念不理解,不过现在好像有点开窍了. 不过英文一般不会存在编码问题,只有中文数据才会有这个问题.比 ...

  9. VHDL实例化过程

    第二步:建立一个名为MUX_0的乘法器 第三步:在程序中例化,看以下程序. -- 该程序用来实现复数的乘法,端口分别定义的复数的 -- 输入的实部和虚部和输出的实部和虚部 LIBRARY IEEE; ...

  10. Last Defence (2014 西安现场赛)

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=94237#problem/K Last Defence Time Limit:3000MS ...