子数组范围和

LC 2104. 子数组范围和

给你一个整数数组 numsnums 中,子数组的范围是子数组中最大元素和最小元素的差值。

返回 nums 中 所有 子数组范围的和

子数组是数组中一个连续 非空 的元素序列。

输入: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

思路:

  • 记录每个值 nums[i] 能成为最小值、最大值的次数 min[i], max[i],子数组范围的和 = nums[i] * (max[i] - min[i])
  • 通过单调栈来维护每个值 nums[i] 能成为最小值和最大值的区间,然后就能根据区间的长度求出这个值出现的次数
  • 求区间:单调栈
    • 求最小值:
      • 通过最小栈从左到右来维护当前值能到达的最左区间,记录到 l[i] 中
      • 通过最小栈从右到左来维护当前值能达到的最右区间,记录到 r[i] 中
      • 整个区间能产生的子区间数为 (i - l[i]) * (r[i] - i)
    • 求最大值:
      • 通过最大栈从左到右来维护当前值能到达的最左区间,记录到 l[i] 中
      • 通过最大栈从右到左来维护当前值能达到的最右区间,记录到 r[i] 中
      • 整个区间能产生的子区间数为 (i - l[i]) * (r[i] - 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
29
30
31
32
33
34
35
36
class Solution {
    int n;
    public long subArrayRanges(int[] nums) {
        n = nums.length;
        long[] min = getCnt(nums, true), max = getCnt(nums, false);
        long res = 0;
        for (int i = 0; i < n; i++) {
            res += nums[i] * (max[i] - min[i]);
        }
        return res;
    }

    long[] getCnt(int[] nums, boolean isMin) {
        long[] l = new long[n], r = new long[n], ans = new long[n];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && (isMin ? nums[stack.peek()] >= nums[i] : nums[stack.peek()] <= nums[i])) {
                stack.pop();
            }
            l[i] = stack.isEmpty() ? -1 : stack.peek();
            stack.push(i);
        }
        stack.clear();
        for (int i = n - 1; i >= 0; i--) {
            while (!stack.isEmpty() && (isMin ? nums[stack.peek()] > nums[i] : nums[stack.peek()] < nums[i])) {
                stack.pop();
            }
            r[i] = stack.isEmpty() ? n : stack.peek();
            stack.push(i);
        }
        for (int i = 0; i < n; i++) {
            ans[i] = 1l * (i - l[i]) * (r[i] - i);
        }
        return ans;
    }
}
updatedupdated2022-06-232022-06-23