【每日一题Day10】LC907子数组的最小值之和

博客围绕子数组的最小值之和【LC907】展开,介绍了暴力解法(超时),其时间复杂度为O(n²),空间复杂度为O(1);重点讲解了单调栈解法,通过寻找元素左右边界计算其对结果的贡献,时间复杂度为O(n),空间复杂度为O(n),还列举了类似题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

子数组的最小值之和【LC907】

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

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

果然是一天难一天简单呀

暴力【超时】

2022/10/28

class Solution {
    public int sumSubarrayMins(int[] arr) {
        long res = 0;
        int len = arr.length;
        for (int i = 0; i < len; i++){
            int min = Integer.MAX_VALUE;
            for (int j = i; j < len; j++){
                min = Math.min(min,arr[j]);
                res += min;
            }
        }
        return  (int)(res % (int)(1e9+7));

    }
}
  • 复杂度

    • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
    • 空间复杂度: O ( 1 ) O(1) O(1)

单调栈

  • 思路:使用单调栈用来寻找每个元素左边第一个小于它的位置L以及右边第一个小于等于它的位置R,找到一个最小值为当前元素的最大区间(L,R],此时该元素对res的贡献为(i-L)*(R-i)*arr[i]

    • 为什么是(i-L)*(R-i)*arr[i]?
      • 在该元素的左边可以选择全部保留或者依次去掉下标为j∈(L,i)的元素的可能性总共有i-L种
      • 在该元素的右边可以选择全部保留或者依次去掉下标为j∈(i,R]的元素的可能性总共有R-i种
      • 当数组内不存在该元素时,左边界为-1,右边界为数组长度
  • 实现

    1.寻找left[i]和right[i]单调栈里元素从栈头到栈底的顺序为递减

    • 初始化left[i] = -1,right[i]= len

    • 首先将栈内大等于于它的元素弹出,对于栈顶元素而言,此时找到了右边第一个小于等于它的位置

      • 将栈顶元素T[st.top()]弹出 right[st.pop()] = i
    • 然后栈内剩下的元素均小于当前元素,对于当前元素,找到了左边第一个小于它的位置

      • left[i] = st.peek()
    • 最后当前元素压入栈内

    2.遍历left[i]和right[i],res+=(i-L)*(R-i)*arr[i]

  • 代码

    class Solution {
        public int sumSubarrayMins(int[] arr) {
            long res = 0;
            int MOD = (int)(1e9 + 7);
            int len = arr.length;
            Deque<Integer> st = new LinkedList<>();
            int[] left = new int[len];
            int[] right = new int[len];
            for (int i = 0; i < len; i++){
                left[i] = -1;
                right[i] = len;
                while (!st.isEmpty() && arr[st.peekFirst()] >= arr[i]){
                    right[st.pollFirst()] = i;
                }
                if (!st.isEmpty()){
                    left[i] = st.peekFirst();
                }
                st.addFirst(i);
            }
            for (int i = 0; i < len; i++){
                res = (res + (long)arr[i]*(i - left[i])*(right[i] - i)) % MOD;
            }
            return  (int)(res);
    
        }
    }
    
  • 复杂度

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( n ) O(n) O(n)

类似的题

子数组最小乘积的最大和【LC1865】

子数组范围和【LC2104】

巫师的的力量和【LC2281】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值