题目描述
给你一个整数数组 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)
的解决方案吗?
解法
方法一:暴力枚举
循环遍历 $i$,作为子数组的起始位置。对于每个 $i$,遍历每个 $j$ 作为子数组的终止位置,此过程中不断求解子数组的最大值、最小值,然后累加差值到结果 ans
中。
最后返回 ans
即可。
时间复杂度 $O(n^2)$。
| class Solution:
def subArrayRanges(self, nums: List[int]) -> int:
ans, n = 0, len(nums)
for i in range(n - 1):
mi = mx = nums[i]
for j in range(i + 1, n):
mi = min(mi, nums[j])
mx = max(mx, nums[j])
ans += mx - mi
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | class Solution {
public long subArrayRanges(int[] nums) {
long ans = 0;
int n = nums.length;
for (int i = 0; i < n - 1; ++i) {
int mi = nums[i], mx = nums[i];
for (int j = i + 1; j < n; ++j) {
mi = Math.min(mi, nums[j]);
mx = Math.max(mx, nums[j]);
ans += (mx - mi);
}
}
return ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long ans = 0;
int n = nums.size();
for (int i = 0; i < n - 1; ++i) {
int mi = nums[i], mx = nums[i];
for (int j = i + 1; j < n; ++j) {
mi = min(mi, nums[j]);
mx = max(mx, nums[j]);
ans += (mx - mi);
}
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13 | func subArrayRanges(nums []int) int64 {
var ans int64
n := len(nums)
for i := 0; i < n-1; i++ {
mi, mx := nums[i], nums[i]
for j := i + 1; j < n; j++ {
mi = min(mi, nums[j])
mx = max(mx, nums[j])
ans += (int64)(mx - mi)
}
}
return ans
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | function subArrayRanges(nums: number[]): number {
const n = nums.length;
let res = 0;
for (let i = 0; i < n - 1; i++) {
let min = nums[i];
let max = nums[i];
for (let j = i + 1; j < n; j++) {
min = Math.min(min, nums[j]);
max = Math.max(max, nums[j]);
res += max - min;
}
}
return res;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | impl Solution {
pub fn sub_array_ranges(nums: Vec<i32>) -> i64 {
let n = nums.len();
let mut res: i64 = 0;
for i in 1..n {
let mut min = nums[i - 1];
let mut max = nums[i - 1];
for j in i..n {
min = min.min(nums[j]);
max = max.max(nums[j]);
res += (max - min) as i64;
}
}
res
}
}
|
方法二:单调栈
枚举每个元素 nums[i]
作为最大值出现在了多少个子数组中,以及作为最小值出现在多少个子数组中。
其中 nums[i]
作为最大值的贡献为正,作为最小值的贡献为负。
我们以 nums[i]
作为最大值为例。找出左侧第一个比 nums[i]
大的位置 left[i]
,右侧第一个大于等于 nums[i]
的位置 right[i]
。计算每个 nums[i]
的贡献 $(i - left[i])\times (right[i] - i)\times arr[i]$,累加得到结果。
时间复杂度 $O(n)$。
相似题目:
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 | class Solution:
def subArrayRanges(self, nums: List[int]) -> int:
def f(nums):
stk = []
n = len(nums)
left = [-1] * n
right = [n] * n
for i, v in enumerate(nums):
while stk and nums[stk[-1]] <= v:
stk.pop()
if stk:
left[i] = stk[-1]
stk.append(i)
stk = []
for i in range(n - 1, -1, -1):
while stk and nums[stk[-1]] < nums[i]:
stk.pop()
if stk:
right[i] = stk[-1]
stk.append(i)
return sum((i - left[i]) * (right[i] - i) * v for i, v in enumerate(nums))
mx = f(nums)
mi = f([-v for v in nums])
return mx + mi
|
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 | class Solution {
public long subArrayRanges(int[] nums) {
long mx = f(nums);
for (int i = 0; i < nums.length; ++i) {
nums[i] *= -1;
}
long mi = f(nums);
return mx + mi;
}
private long f(int[] nums) {
Deque<Integer> stk = new ArrayDeque<>();
int n = nums.length;
int[] left = new int[n];
int[] right = new int[n];
Arrays.fill(left, -1);
Arrays.fill(right, n);
for (int i = 0; i < n; ++i) {
while (!stk.isEmpty() && nums[stk.peek()] <= nums[i]) {
stk.pop();
}
if (!stk.isEmpty()) {
left[i] = stk.peek();
}
stk.push(i);
}
stk.clear();
for (int i = n - 1; i >= 0; --i) {
while (!stk.isEmpty() && nums[stk.peek()] < nums[i]) {
stk.pop();
}
if (!stk.isEmpty()) {
right[i] = stk.peek();
}
stk.push(i);
}
long s = 0;
for (int i = 0; i < n; ++i) {
s += (long) (i - left[i]) * (right[i] - i) * nums[i];
}
return s;
}
}
|
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 | class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
long long mx = f(nums);
for (int i = 0; i < nums.size(); ++i) nums[i] *= -1;
long long mi = f(nums);
return mx + mi;
}
long long f(vector<int>& nums) {
stack<int> stk;
int n = nums.size();
vector<int> left(n, -1);
vector<int> right(n, n);
for (int i = 0; i < n; ++i) {
while (!stk.empty() && nums[stk.top()] <= nums[i]) stk.pop();
if (!stk.empty()) left[i] = stk.top();
stk.push(i);
}
stk = stack<int>();
for (int i = n - 1; i >= 0; --i) {
while (!stk.empty() && nums[stk.top()] < nums[i]) stk.pop();
if (!stk.empty()) right[i] = stk.top();
stk.push(i);
}
long long ans = 0;
for (int i = 0; i < n; ++i) {
ans += (long long) (i - left[i]) * (right[i] - i) * nums[i];
}
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 | func subArrayRanges(nums []int) int64 {
f := func(nums []int) int64 {
stk := []int{}
n := len(nums)
left := make([]int, n)
right := make([]int, n)
for i := range left {
left[i] = -1
right[i] = n
}
for i, v := range nums {
for len(stk) > 0 && nums[stk[len(stk)-1]] <= v {
stk = stk[:len(stk)-1]
}
if len(stk) > 0 {
left[i] = stk[len(stk)-1]
}
stk = append(stk, i)
}
stk = []int{}
for i := n - 1; i >= 0; i-- {
for len(stk) > 0 && nums[stk[len(stk)-1]] < nums[i] {
stk = stk[:len(stk)-1]
}
if len(stk) > 0 {
right[i] = stk[len(stk)-1]
}
stk = append(stk, i)
}
ans := 0
for i, v := range nums {
ans += (i - left[i]) * (right[i] - i) * v
}
return int64(ans)
}
mx := f(nums)
for i := range nums {
nums[i] *= -1
}
mi := f(nums)
return mx + mi
}
|