来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-subarray-ranges

题目描述

给你一个整数数组 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(n2)

还有一种巧妙的方法可以将时间复杂度压缩到O(n)。

对于第i个数ai,如果左边第一个比他小的数下标为left,第一个比他小的数下标位right,那么(left,right)中所有的子数组最小值都是ai,在(left,right)中共有(right - i) * (i - left) 个子数组,那么(left, right)范围内子数组最小值的和为(right - i) * (i - left) * ai,同理可以求出(left, right)范围内子数组最大值的和,两个相减就可以求出(left, right)范围内的范围和。

问题转化为了如何第i个数左边小值和大值及右边的小值和大值,使用单调栈一次遍历便可以分别求得这四个值,并且用vector将下标存起来。

代码展示

暴力法:

class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
long long ret = 0;
for (int i = 0; i < n; i++) {
int minVal = INT_MAX, maxVal = INT_MIN;
for (int j = i; j < n; j++) {
minVal = min(minVal, nums[j]);
maxVal = max(maxVal, nums[j]);
ret += maxVal - minVal;
}
}
return ret;
}
};

单调栈+数学:

class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int n = nums.size();
long long ret = 0;
vector<int> viLeftMin(n), viRightMin(n), viLeftMax(n), viRightMax(n);
stack<int> siMax, siMin;
for(int i = 0; i < n; i++)
{
while(!siMin.empty() && nums[siMin.top()] > nums[i])
siMin.pop();
viLeftMin[i] = siMin.empty()? -1: siMin.top();
siMin.push(i); while(!siMax.empty() && nums[siMax.top()] <= nums[i])
siMax.pop();
viLeftMax[i] = siMax.empty()? -1: siMax.top();
siMax.push(i);
}
siMax = stack<int>();
siMin = stack<int>();
for(int i = n - 1; i >= 0; i--)
{
while(!siMin.empty() && nums[siMin.top()] >= nums[i])
siMin.pop();
viRightMin[i] = siMin.empty()? n: siMin.top();
siMin.push(i); while(!siMax.empty() && nums[siMax.top()] < nums[i])
siMax.pop();
viRightMax[i] = siMax.empty()? n: siMax.top();
siMax.push(i);
} for(int i = 0; i < n; i++)
{
ret += ((((long long)viRightMax[i] - i) * (i - viLeftMax[i])) - (((long long)viRightMin[i] - i) * (i - viLeftMin[i])))* nums[i];
}
return ret;
}
};

运行结果

LeetCode-2104 子数组范围和的更多相关文章

  1. LeetCode 643. 子数组最大平均数 I(Maximum Average Subarray I)

    643. 子数组最大平均数 I 643. Maximum Average Subarray I 题目描述 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. LeetCo ...

  2. Leetcode 643.子数组最大平均数I

    子数组最大平均数I 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.75 解释: ...

  3. Java实现 LeetCode 643 子数组最大平均数 I(滑动窗口)

    643. 子数组最大平均数 I 给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.7 ...

  4. [LeetCode] Minimum Size Subarray Sum 最短子数组之和

    Given an array of n positive integers and a positive integer s, find the minimal length of a subarra ...

  5. LeetCode 560. Subarray Sum Equals K (子数组之和等于K)

    Given an array of integers and an integer k, you need to find the total number of continuous subarra ...

  6. [LeetCode] Maximum Sum of 3 Non-Overlapping Subarrays 三个非重叠子数组的最大和

    In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum. E ...

  7. [LeetCode] Maximum Average Subarray II 子数组的最大平均值之二

    Given an array consisting of n integers, find the contiguous subarray whose length is greater than o ...

  8. [LeetCode] Subarray Product Less Than K 子数组乘积小于K

    Your are given an array of positive integers nums. Count and print the number of (contiguous) subarr ...

  9. [LeetCode] Maximum Average Subarray I 子数组的最大平均值

    Given an array consisting of n integers, find the contiguous subarray of given length k that has the ...

  10. [LeetCode] Subarray Sum Equals K 子数组和为K

    Given an array of integers and an integer k, you need to find the total number of continuous subarra ...

随机推荐

  1. VSCode编辑器极简使用入门

    VSCode(Visual Studio Code)是一款开源.跨平台.轻量级的代码编辑器,具有非常丰富的插件生态.他本身就是JavaScript + Electron ( /ɪˈlektrɒn/电子 ...

  2. 如何优化大场景实时渲染?HMS Core 3D Engine这么做

    在先前举办的华为开发者大会2022(HDC)上,华为通过3D数字溪村展示了自有3D引擎"HMS Core 3D Engine"(以下简称3D Engine)的强大能力.作为一款高性 ...

  3. Jmeter 之随机控制器与随机顺序控制器

    一.随机控制器 随机控制器相当于python 中的 random.choice(),随机选取其中的一个取样器(业务执行) 实例中随机运行了其中的一个请求 二.随机顺序控制器 随机顺序控制器相当于pyt ...

  4. 【深入浅出 Yarn 架构与实现】4-2 RM 管理 Application Master

    上一篇文章对 ResourceManager 整体架构和功能进行了讲述.本篇将对 RM 中管理 Application Master 的部分进行深入的讲解. 下面将会介绍 RM 与 AM 整体通信执行 ...

  5. asp前端无法获取后端中select *查询带出来的全部字段

    1.环境 前端:ASP.vbscript 后端:vb 数据库:Sql Server 2.问题描述 最近在做需求时碰到一个很奇怪的问题,后端通过select *查询带出来的字段,在前端只能获取到部分字段 ...

  6. 既然有MySQL了,为什么还要有MongoDB?

    大家好,我是哪吒,最近项目在使用MongoDB作为图片和文档的存储数据库,为啥不直接存MySQL里,还要搭个MongoDB集群,麻不麻烦? 让我们一起,一探究竟,了解一下MongoDB的特点和基本用法 ...

  7. CSS 奇思妙想之酷炫倒影

    在 CSS 中,倒影是一种比较常见的效果.今天,我们就将尝试,使用 CSS 完成各类不同的倒影效果,话不多说,直接进入主题. 实现倒影的两种方式 首先,快速过一下在 CSS 中,实现倒影的 2 种方式 ...

  8. [cocos2d-x]关于CC_CALLBACK

    CC_CALLBACK的代码 // new callbacks based on C++11 #define CC_CALLBACK_0(__selector__,__target__, ...) s ...

  9. 【Azure Developer】在Github Action中使用Azure/functions-container-action@v1配置Function App并成功部署Function Image

    问题描述 使用Github Action,通过 Azure/functions-container-action@v1 插件来完成 yaml 文件的配置,并成功部署Function Image 的过程 ...

  10. 经典问题 1 —— DAG 上区间限制拓扑序

    问题描述 给定一个 DAG,求一个拓扑序,使得节点 \(i\) 的拓扑序 \(\in [l_i,r_i]\). 题解 首先进行一个预处理:对于所有 \(u\),令 \(\forall (v,u)\in ...