2104. 子数组范围和

207 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

不是因为看到了希望才坚持,而是因为坚持了才能看到希望。共勉

每日刷题第55天 2021.03.04

2104. 子数组范围和

题目描述

  • 给你一个整数数组 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]
    • 子区间中作为最大值的次数:
    • 子区间中作为最小值的次数:

总结

  • 单调栈的巧妙使用