leetcode:子数组的最小值之和

一、题目

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

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

来源:力扣

二、思路

1.读完题之后先尝试了暴力解题,即依次遍历出所有连续子数组的最小值然后求和,提交之后在第68样例超时。

2.优化时间复杂度之后的思路:对数组中的每一个数找到他对应的“辐射区域”(与之相邻的连续子数组最小值都是这个数),求和时只需算每一个数的辐射区域的子数组个数✖该数即可。

每个中心点包含的子序列个数计算公式:(index(中心点) - index(辐射区第1个整数) + 1) * (index(辐射区最后1个整数) - index(中心点) + 1) 

确定辐射区域:采用单调栈的方式,因为计算辐射区内的子序列时,是需要通过下标计算的,所以堆栈中存储的是数组arr中元素的下标。然后,遍历整个数组arr,如果堆栈为空,那么直接入栈;如果堆栈不为空,则进行如下操作:

如果栈顶元素 > arr[i] :则弹出栈顶元素n,那么针对于这个n来说,它的辐射区域就是(新的栈顶元素, i)[注]左开右开区间。
如果栈顶元素 <= arr[i] :则arr[i]直接入栈。

 

三、代码

方法一:

class Solution:
    def sumSubarrayMins(self, arr: List[int]) -> int:
        L=len(arr)
        sum1=0
        K=1
        b=[]
        for i in range(L):
            a=[]
            for k in range(L-i):
                while k>=0:
                    a.append(arr[i+k])
                    k -=1
                b.append(min(a))
        for i in range(len(b)):
            sum1=sum1+b[i]
        return sum1

方法二: 

 

class Solution:
    def sumSubarrayMins(self, arr: List[int]) -> int:
        n = len(arr)
        left = [-1] * n
        right = [n] * n
        stk = []
        for i, v in enumerate(arr):
            while stk and arr[stk[-1]] >= v:
                stk.pop()
            if stk:
                left[i] = stk[-1]
            stk.append(i)

        stk = []
        for i in range(n - 1, -1, -1):
            while stk and arr[stk[-1]] > arr[i]:
                stk.pop()
            if stk:
                right[i] = stk[-1]
            stk.append(i)
        mod = 10**9 + 7
        return sum((i - left[i]) * (right[i] - i) * v for i, v in enumerate(arr)) % mod
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值