题目
给你一个整数数组 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-subarray-ranges
解题
1.暴力求解
由例子我们就可以看出,暴力求解只需要两个for循环就可以完成,只是注意最大值和最小值的赋值需要在两个for循环之间,这样才能达到循环一个丢一个的目的。
var subArrayRanges = function (nums) {
let sum = 0;
// 4 -2
// 4 -2 -3
// 4 -2 -3 4
// 4 -2 -3 4 1
for (let i = 0; i < nums.length; i++) {
// console.log(1111);
let maxNum = nums[i];
let minNum = nums[i + 1];
if (minNum > maxNum) {
maxNum = nums[i + 1];
minNum = nums[i];
}
for (let j = i + 1; j < nums.length; j++) {
maxNum = Math.max(maxNum, nums[j]);
minNum = Math.min(minNum, nums[j]);
sum += maxNum - minNum;
// console.log(sum);
}
}
return sum
}
2.单调栈
算法小白第一次接触单调栈,直接上官方代码。
var subArrayRanges = function (nums) {
const n = nums.length;
const minLeft = new Array(n).fill(0);
const minRight = new Array(n).fill(0);
const maxLeft = new Array(n).fill(0);
const maxRight = new Array(n).fill(0);
let minStack = [];
let maxStack = [];
for (let i = 0; i < n; i++) {
while (minStack.length && nums[minStack[minStack.length - 1]] > nums[i]) {
minStack.pop();
}
minLeft[i] = minStack.length === 0 ? -1 : minStack[minStack.length - 1];
minStack.push(i);
// 如果 nums[maxStack[maxStack.length - 1]] == nums[i], 那么根据定义,
// nums[maxStack[maxStack.length - 1]] 逻辑上小于 nums[i],因为 maxStack[maxStack.length - 1] < i
while (maxStack.length && nums[maxStack[maxStack.length - 1]] <= nums[i]) {
maxStack.pop();
}
maxLeft[i] = maxStack.length === 0 ? -1 : maxStack[maxStack.length - 1];
maxStack.push(i);
}
minStack = [];
maxStack = [];
for (let i = n - 1; i >= 0; i--) {
// 如果 nums[minStack[minStack.length - 1]] == nums[i], 那么根据定义,
// nums[minStack[minStack.length - 1]] 逻辑上大于 nums[i],因为 minStack[minStack.length - 1] > i
while (minStack.length && nums[minStack[minStack.length - 1]] >= nums[i]) {
minStack.pop();
}
minRight[i] = minStack.length === 0 ? n : minStack[minStack.length - 1];
minStack.push(i);
while (maxStack.length && nums[maxStack[maxStack.length - 1]] < nums[i]) {
maxStack.pop();
}
maxRight[i] = maxStack.length === 0 ? n : maxStack[maxStack.length - 1];
maxStack.push(i);
}
let sumMax = 0,
sumMin = 0;
for (let i = 0; i < n; i++) {
sumMax += (maxRight[i] - i) * (i - maxLeft[i]) * nums[i];
sumMin += (minRight[i] - i) * (i - minLeft[i]) * nums[i];
}
return sumMax - sumMin;
};
单调栈如何理解可以参考下面大佬的文章,私以为柱状图中的最大矩形是理解单调栈非常直观的一个例子。