2104. 子数组范围和
Difficulty
Tags
URL
https://leetcode.cn/problems/sum-of-subarray-ranges/comments/
Star
给你一个整数数组 nums 。nums 中,子数组的 范围 是子数组中最大元素和最小元素的差值。
返回 nums 中 所有 子数组范围的 和 。
子数组是数组中一个连续 非空 的元素序列。
示例 1:
输入:nums = [1,2,3] 输出:4 解释:nums 的 6 个子数组如下所示: [1],范围 = 最大 - 最小 = 1 - 1 = 0 [2],范围 = 2 - 2 = 0 [3],范围 = 3 - 3 = 0 [1,2],范围 = 2 - 1 = 1 [2,3],范围 = 3 - 2 = 1 [1,2,3],范围 = 3 - 1 = 2 所有范围的和是 0 + 0 + 0 + 1 + 1 + 2 = 4
示例 2:
输入:nums = [1,3,3] 输出:4 解释:nums 的 6 个子数组如下所示: [1],范围 = 最大 - 最小 = 1 - 1 = 0 [3],范围 = 3 - 3 = 0 [3],范围 = 3 - 3 = 0 [1,3],范围 = 3 - 1 = 2 [3,3],范围 = 3 - 3 = 0 [1,3,3],范围 = 3 - 1 = 2 所有范围的和是 0 + 0 + 0 + 2 + 0 + 2 = 4
示例 3:
输入:nums = [4,-2,-3,4,1] 输出:59 解释:nums 中所有子数组范围的和是 59
提示:
- 1 <= nums.length <= 1000
- -109 <= nums[i] <= 109
进阶:你可以设计一种时间复杂度为 O(n) 的解决方案吗?
法 1 单调栈
思路
单调栈,首先转换题目:子数组范围和 等于所有子数组(即所有区间)的最大值的和 减去 所有区间最小值的和.参考 907. 子数组的最小值之和
所以我们可以分别计算所有区间的最大值的和以及所有区间的最小值的和
题解
class Solution: def subArrayRanges(self, nums: List[int]) -> int: B = 10**9 min_sum = 0 nums = [-B-1] + nums + [-B-1] stack = [] # 找到两边比nums[stack[-1]] 小的元素, # 然后在这个范围内的子数组的最小值就是nums[stack[-1]] for i in range(0, len(nums)): while stack and nums[i] < nums[stack[-1]]: idx = stack.pop() min_sum += nums[idx] * (idx-stack[-1]) * (i-idx) stack.append(i) max_sum = 0 nums[0] = B+1 nums[-1] = B+1 stack = [] # 在nums中找到两边比nums[stack[-1]] 大的元素, # 然后在这个范围内的子数组的最大值就是nums[stack[-1]] for i in range(0, len(nums)): while stack and nums[i] > nums[stack[-1]]: idx = stack.pop() max_sum += nums[idx] * (i-idx) * (idx-stack[-1]) stack.append(i) return max_sum-min_sum