2104. 子数组范围和

exiaohu 于 2022-03-04 发布

题目链接:2104. 子数组范围和

假设有 $m$ 个子数组,最终的表达式为 $m$ 个等式 $\sum_{j=1}^{m}{\max_j - \min_j}$ 之和。

若数组中第 $i$ 个数 $n_i$:

可统计 $n_i$ 作为子数组最大值的次数 $cnt_{max, i}$ 和作为最小值的次数 $cnt_{min, i}$,$(cnt_{max, i} - cnt_{min, i}) \times n_i$ 的结果就是 $n_i$ 在上述加和式中的贡献。

使用单调栈计算 $cnt_{max, i}$ 和 $cnt_{min, i}$:

from typing import List


class Solution:
    def cnt(self, nums: List[int], is_min: bool):
        lft, rgt, lstk, rstk = [], [], [], []
        for i in range(len(nums)):
            while lstk and (nums[lstk[-1]] >= nums[i] if is_min else nums[lstk[-1]] <= nums[i]): lstk.pop()
            lft.append(-1 if not lstk else lstk[-1])
            lstk.append(i)

        for i in range(len(nums) - 1, -1, -1):
            while rstk and (nums[rstk[-1]] > nums[i] if is_min else nums[rstk[-1]] < nums[i]): rstk.pop()
            rgt.append(len(nums) if not rstk else rstk[-1])
            rstk.append(i)

        return [(i - l) * (r - i) for i, (l, r) in enumerate(zip(lft, rgt[::-1]))]

    def subArrayRanges(self, nums: List[int]) -> int:
        print(self.cnt(nums, False), self.cnt(nums, True))
        return sum((ma - mi) * n for ma, mi, n in zip(self.cnt(nums, False), self.cnt(nums, True), nums))