leetCode第2104题 子数组范围和
链接:https://leetcode-cn.com/problems/sum-of-subarray-ranges
给你一个整数数组 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
务实一点,先把题目的意思、子数这个理念先搞懂。
子数不是子集,是一个类似滑动窗口的东西。
窗口会不断移动,当移动到最后时,窗口会扩大,然后继续移动。
这这窗口内的数就是这个列表的子数,子数在列表中一定是连续的
这个滑动窗口如何实现呢?当窗口后移时,后面加了一个元素,前面减去了一个元素。这显然就可以利用队列实现。
然后求队列中的最大值和最小值,求出其差值即可。
利用这种滑动窗口不断遍历,不断求最大值和最小值,实在过于冗余,那么势必会导致超时。
但我还是分享一下它的实现代码
class Solution:
def subArrayRanges(self, nums: [int]) -> int:
if len(nums) < 2:
return 0
queue,res = [],[]
for i in range(1,len(nums)):
queue = nums[:i+1]
res.append(self.list_range(queue))
for j in range(i+1,len(nums)):
queue.pop(0)
queue.append(nums[j])
res.append(self.list_range(queue))
return sum(res)
def list_range(self,nums:list) -> int:
if len(nums) <2:
return 0
maxx = max(nums)
minn = min(nums)
return maxx - minn
子数是列表中一段连续的数子,那么知道这个概念之后,其实完全没有必要用滑动窗口啊,我们可以定下左边界,之后不断加大右边界不就行了么。
然后将左边界右移
那么最大值和最小值怎么办?只要设定max和min记录当前最大最小值,然后和新进来的元素比较大小,然后进行更新即可。完全不必像滑动窗口一样没一次变化都需要遍历才能求最大最小值。
class Solution:
def subArrayRanges(self, nums: [int]) -> int:
if len(nums) < 2:
return 0
queue,res = [],[]
for i in range(len(nums)):
maxx, minn = -10**10,10**10
for j in range(i,len(nums)):
maxx = max(maxx,nums[j])
minn = min(minn,nums[j])
res.append(maxx-minn)
return sum(res)