Sum of Subarray Minimums

Sum of Subarray Minimums

Question:

请添加图片描述

思路:

这道题的代码很简短, 很容易写. 但是这背后的概念不太好理解. 这题虽然是medium但难度比得上hard

首先我们要打破一个常规思想, 就是找subarray最小值的和. 我们最直接的反应肯定是sliding window, 或者是 brute force, 先找遍所有的subarray, 然后再找到所有的最小值加在一起.

这道题其实有更nb的方法, 但需要我们换个角度想答案, 我们这道题可以这么解. 我们遍历每一个element, 然后找到所有subarray最小element 是当前element的数量. 之后再用当前element * 数量 加到 sum里去。
这样一来就可以实现一遍forloop O(N)
然后我们再思考怎么能找到element 的 subarray数量呢.
我们可以发现我们可以找到一个rang 就是当前element 为中间, 往左找和往右找比当前element 更小的值的index, 我们定义这两个index 为i, j.
那么请问nums[I] ~ nums[j] 是不是就是在这个range中 element是最小的.
for example

2 4 6 7 3 5 1
我们找element 为 3 的 range,
那么往左 i = 0, nums[I] = 2 是 range 的 left bound
往右i = 6, nums[j] = 1 是range 的 right bound
那么3 在range(0, 6) 中间就是最小的值.
ok
那么我们就可以通过

4 ,6, 7 (to the left)
5, 1(to the right)
得到一共在这个range内 包含3 可以有多少个subarray
4, 3, 5
4, 3, 1
6, 3, 5,
6, 3, 1


一共是 3 * 2 = 6种
不, 还没够
其实还有可能3 的 left 不选 或者3 的right 不选。就是
3, 5
3, 1
4,3
6, 3
7, 3
3
那么就相当于
_,4 ,6, 7 (to the left)
_,5, 1(to the right)

一共是 4 * 3 = 12 个 subarray
那么我们就能算到, 3为最小subarray的数量是12个.
然后我们就可以3*12 = 36.
那么这个是找的3的.
我们用同样的方法找全部element的 subarray数量.
用monotic increasing stack, 当insert element的时候把stack里比insert的element更大的element pop 出去. 此时pop出去的element我们就能得知, 它的下一个smaller element 就是我们此时正在insert的number, 而它的左边一个smaller的number恰好就是stack里下面的那一个element
那么我们找到了pop出来的这个element的左边下一个smaller和右边下一个smaller. 那就可以得到range了
ye!!!

如果pop出来的element是最后一个element, 接着stack就空了, 那么这个element 左边的bound 就是index = -1. 没问题的.

具体monotic stack里边的细节 看这道题在leetcode 的soluiton.

class Solution {
    public int sumSubarrayMins(int[] arr) {
        int MOD = 1000000007;

        Stack<Integer> stack = new Stack<>();
        long sumOfMinimums = 0;

        // building monotonically increasing stack
        for (int i = 0; i <= arr.length; i++) {

            // when i reaches the array length, it is an indication that
            // all the elements have been processed, and the remaining
            // elements in the stack should now be popped out.

            while (!stack.empty() && (i == arr.length || arr[stack.peek()] >= arr[i])) {

                // Notice the sign ">=", This ensures that no contribution
                // is counted twice. rightBoundary takes equal or smaller 
                // elements into account while leftBoundary takes only the
                // strictly smaller elements into account

                int mid = stack.pop();
                int leftBoundary = stack.empty() ? -1 : stack.peek();
                int rightBoundary = i;

                // count of subarrays where mid is the minimum element
                long count = (mid - leftBoundary) * (rightBoundary - mid) % MOD;

                sumOfMinimums += (count * arr[mid]) % MOD;
                sumOfMinimums %= MOD;
            }
            stack.push(i);
        }

        return (int) (sumOfMinimums);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值