📌  相关文章
📜  排序数组的所有子数组的最小元素的总和(1)

📅  最后修改于: 2023-12-03 15:25:55.872000             🧑  作者: Mango

排序数组的所有子数组的最小元素的总和

问题描述

给定一个由非负整数构成的长度为 n 的数组 nums ,代表一个由 nums[0]nums[n - 1] 升序排列的数组。

请你返回每个 子数组 的最小元素的 总和

其中,子数组定义为原数组中的一个连续的下标序列。

请注意,大小为 k 的子数组共有 n - k + 1 个,其中 k 是子数组的大小。

例如,[1,2,3][2,3][1,2] 都是不同的子数组。

解决方案

对于每个子数组,我们需要找到其中的最小值并加到总和中。对于长度为 k 的子数组,最小值的位置一定是在该子数组中,在该子数组的所有元素中遍历一遍即可。因此,我们可以使用两层循环遍历所有子数组和子数组中的元素,时间复杂度为 $O(n^2)$。

但是,我们可以利用单调栈来优化此算法。具体地,我们维护一个单调递增栈 stack,遍历原数组 nums 时,如果当前元素 num 大于栈顶元素,则直接将其入栈;否则,我们将栈顶元素弹出,并加上弹出元素在原数组中左边、右边第一个小于其的元素的位置之积,加到总和中。我们可以证明,这样的操作可以保证在每个子数组中都找到了最小值。

据此,我们可以使用单调栈在 $O(n)$ 时间内遍历原数组,得到所有子数组的最小值的总和。

代码实现

以下是 Python 代码实现:

class Solution:
    def sumSubarrayMins(self, nums: List[int]) -> int:
        """
        :type nums: List[int]
        :rtype: int
        """
        stack = []
        res = 0
        nums = [0] + nums + [0]
        for i, num in enumerate(nums):
            while stack and nums[stack[-1]] > num:
                j = stack.pop()
                k = stack[-1]
                res += nums[j] * (i - j) * (j - k)
            stack.append(i)
        return res % (10**9 + 7)
总结

本问题通过单调栈的优化,提高了算法的时间复杂度。同时,本问题也展示了单调栈在解决相关问题中的威力。