CC

自然万物都趋向从有序变得无序

0%

leetcode-2104 子数组范围和

2104. 子数组范围和 - 力扣(LeetCode) (leetcode-cn.com)

题意

给你一个整数数组nums。返回nums中所有子数组范围的和 。

子数组的 范围 是子数组中最大元素和最小元素的差值。

思路

首先想到的解法是暴力即可,在枚举子数组的同时,维护最大值和最小值。

但暴力时间复杂度为O(n2)O(n^2)

进一步分析题意,可以得到,实际上的最终答案为所有子数组的最大值的和减去所有子数组的最小值的和。

因此我们可以枚举数组的每个数作为子数组的最大值和最小值时对答案的贡献。

当nums[i]作为最大值时,需要找到nums[i]左边第一个比它大的数的下标lmax,和右边第一个比它大的数的下标rmax,此时nums[i]对答案的贡献为 (i-lmax)*(i-rmax)*nums[i]。

同理,当nums[i]作为最小值时,需要找到nums[i]左边第一个比它小的数的下标lmin,和右边第一个比它小的数的下标rmin,此时nums[i]对答案的贡献为 -(i-lmin)*(i-rmin)*nums[i]。

可以用单调栈维护上述过程。

暴力代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
*@File Name :leetcode-2104.cpp
*@Author :cc
*@Version :1.0.0
*@Date :2022/3/4 9:06
*@Description :
*@Function List :
*@History :
*/

#include "vector"
#include "algorithm"
using namespace std;

class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long ans = 0;
for(int i = 0; i < nums.size(); i++){
int minx = nums[i], maxx = nums[i];
for(int j = i+1; j < nums.size(); j++){
minx = min(minx, nums[j]);
maxx = max(maxx, nums[j]);
ans += maxx-minx;
}
}return ans;
}
};

单调栈代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
*@File Name :leetcode-2104.cpp
*@Author :cc
*@Version :1.0.0
*@Date :2022/3/4 9:06
*@Description :
*@Function List :
*@History :
*/

#include "vector"
#include "algorithm"
#include "stack"

using namespace std;

class Solution {
public:
long long subArrayRanges(vector<int> &nums) {
long long ans = 0;
int n = nums.size();
vector<int> lmin(n, 0), lmax(n, n - 1);
stack<int> minStack, maxStack;
for (int i = 0; i < n; i++) {
while (!minStack.empty() && nums[minStack.top()] > nums[i])
minStack.pop();
lmin[i] = minStack.empty() ? -1 : minStack.top();
minStack.emplace(i);

while (!maxStack.empty() && nums[maxStack.top()] < nums[i])
maxStack.pop();
lmax[i] = maxStack.empty() ? -1 : maxStack.top();
maxStack.emplace(i);
}

while (!minStack.empty()) minStack.pop();
while (!maxStack.empty()) maxStack.pop();

for (int i = n - 1; i >= 0; i--) {
while (!minStack.empty() && nums[minStack.top()] >= nums[i])
minStack.pop();
int minr = minStack.empty() ? n : minStack.top();
minStack.emplace(i);
while (!maxStack.empty() && nums[maxStack.top()] <= nums[i])
maxStack.pop();
int maxr = maxStack.empty() ? n : maxStack.top();
maxStack.emplace(i);
ans = ans + (long long) ((maxr - i) * (i - lmax[i]) - (minr - i) * (i - lmin[i])) * nums[i];
}
return ans;
}
};