Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
不是因为看到了希望才坚持,而是因为坚持了才能看到希望。共勉
每日刷题第55天 2021.03.04
2104. 子数组范围和
- leetcode原题链接:leetcode-cn.com/problems/su…
- 难度:中等
- 方法:爆搜(维护最大值和最小值)、单调栈
题目描述
- 给你一个整数数组 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
AC代码
- 常规做法,爆搜+维护最大和最小值
var subArrayRanges = function(nums) {
let ans = 0;
let len = nums.length;
let max = nums[0];
let min = nums[0];
for(let i = 0; i < len; i++) {
min = nums[i];
max = nums[i];
for(let j = i + 1; j < len; j++) {
// 最大值和最小值相减,维护一个最大值
if(max < nums[j]){
max = nums[j];
}
if(min > nums[j]){
min = nums[j];
}
ans += max - min;
}
}
return ans;
};
进阶: 你可以设计一种时间复杂度为 O(n) 的解决方案吗?
- 进阶的思路:解决过程中使用到了单调栈,但是最重要的还是解题的思路,因为数据结构是只是用于解决问题的一种处理方式。(先要想到如何解决,才来决定使用哪种数据结构)
- 题目中要求返回:所有子数组中最大元素和最小元素的差值的和。
- 所有子数组中的最大元素和最小元素的差值的和
= max总 - min总 - 数组中每个元素,对于最终答案的贡献值:
nums[i] * max次数 - nums[i] * min次数 - 那么此时问题就转换为:求解数组中的每个元素在子区间中作为最大值、最小值的次数。
- 举例:
[1,2,3] - 子区间中作为最大值的次数:
- 子区间中作为最小值的次数:
- 举例:
总结
- 单调栈的巧妙使用