来源:力扣(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. 【JVM】根节点枚举与安全点

    本文已收录至Github,推荐阅读 Java随想录 微信公众号:Java随想录 CSDN: 码农BookSea 转载请在文首注明出处,如发现恶意抄袭/搬运,会动用法律武器维护自己的权益.让我们一起维护 ...

  2. Java求值策略

    为什么说Java不存在引用传递? 在Java语言中,存在两种数据类型,一种是基本类型,如int.byte等8种基本类型,一种是引用类型,如String.Integer等.这两种数据类型区别就在于,基本 ...

  3. 一文了解 Dubbo 3 配置工作原理

    以下是一个 Dubbo 属性配置的例子 dubbo-spring-boot-samples ## application.properties # Spring boot application sp ...

  4. C语言写的 史上最公平的投票系统

    #include<stdio.h> #include<string.h> #define MMM 4 struct student { char name[10]; int c ...

  5. Spring MVC的运行流程

    Spring MVC的运行流程 摘要:本文档主要结合官方给出的Spring MVC流程图结合一个简单的Spring MVC实例,分析并介绍了Spring MVC的运行流程. 目录 Spring MVC ...

  6. 失配树学习笔记 | P5829 【模板】失配树

    简介 失配树(简称 Fail 树),是基于 KMP 的算法,可以高效的解决复杂的字符串前缀后缀关系问题. 前置知识: KMP 算法(求失配数组) 最近公共祖先(LCA) 希望大家看完这篇文章后可以理解 ...

  7. LIS求解(包括优化)

    首先,让我来看看LIS问题 Description 一个数的序列 bi,当 b1 < b2 < ... < bS 的时候,我们称这个序列是上升的.对于给定的一个序列(a1,a2,.. ...

  8. 【力扣】剑指 Offer II 092. 翻转字符

    题目 解题思路 一个很暴力的想法,在满足单调递增的前提下,使每一位分别取 1 或 0,去看看哪个结果小. 递归函数定义int dp(StringBuilder sb, int ind, int pre ...

  9. IntelliJ中高效重构的 10 个快捷方式

    前言 在日常的开发工作中,我们经常需要重构,重构可以让我们写出的代码更上一层楼.所以,我会借助IntelliJ提供的一些功能,帮助我高效进行重构.这里是我推荐10个快捷方式,也是我每天都在使用的,非常 ...

  10. Axure 列表左右滑动交互-删除、置顶

    Axure 列表左右滑动交互 左滑:删除.标记 右滑:置顶.回复 拖一个动态面板,命名为[滑动面板],添加三个状态,并分别命名为:正常状态.向左状态.向右状态 添加元件 正常状态 向左状态 将[正常状 ...