【Leetcode每日一题:907.子数组的最小值之和~~~单调栈】

题目描述

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。

由于答案可能很大,因此 返回答案模 10^9 + 7 。

示例 1:

输入:arr = [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。
示例 2:

输入:arr = [11,81,94,43,3]
输出:444

提示:

1 <= arr.length <= 3 * 104
1 <= arr[i] <= 3 * 104

解题思路

  1. 这是一道通过单调栈来解决的问题,题目要求我们求得一个数组中所有子数组中的最小值,然后求得它的累加和。
  2. 我们的求解思路是以每一个数作为当前子数组中的最小值,然后找寻左边比自身位置小的元素下标,同理,右边也是,找到比它还小的位置元素的下标。通过元素下标的位置,根据乘法原理求得对当前有多少子数组是以当前位置作为最小值的结果,贡献就是:当前位置的元素*个数。
  3. 解决找到某一个数右边比它大,或者小,左边比它大,或者小,最快的解决方式就是单调栈。

实现代码

class Solution {
    private static final long MOD = (long) 1e9 + 7;

    public int sumSubarrayMins(int[] arr) {
        int n = arr.length;
        int[] left = new int[n];
        int[] right = new int[n];
        Arrays.fill(right, n);
        Deque<Integer> st = new ArrayDeque<Integer>();
        st.push(-1); 
        for (int i = 0; i < n; ++i) {
            //寻找右边小于当前位置第一个元素
            while (st.size() > 1 && arr[st.peek()] >= arr[i])
                right[st.pop()] = i; 
            left[i] = st.peek();
            st.push(i);
        }
        long ans = 0L;
        for (int i = 0; i < n; ++i)
            //乘法原理计算结果
            ans += (long) arr[i] * (i - left[i]) * (right[i] - i); 
        return (int) (ans % MOD);
    }
}

运行结果

【Leetcode每日一题:907.子数组的最小值之和~~~单调栈】_第1张图片

你可能感兴趣的:(LeetCode每日一题打卡,leetcode,算法,单调栈,java,子数组)