当前位置:网站首页>leetcode:2104. 子数组范围和
leetcode:2104. 子数组范围和
2022-06-24 21:21:00 【OceanStar的学习笔记】
题目来源
题目描述


class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
}
};
题目解析
单调栈
因为需要最大元素、最小元素,所以应该想办法把问题转换为单调栈。
由于我们要求的是所有子数组最大元素和最小元素的差值。因此,我们考虑每个元素成为了多少个区间的最大值,还有多少个区间的最小值。前者的数量就是该元素在累计求和中被加的次数,后者则是被减的次数。
这样我们只需要一种遍历一遍的方式获得每个元素是多少个区间的最大最小值即可在O(n)的时间里求出结果。
考虑一个具体的例子: [ 2 , 3 , 5 , 4 , 10 , 2 ] [2, 3, 5, 4, 10, 2] [2,3,5,4,10,2]
- 我们考虑中间的某个数字4,它是多少区间的最大值呢?首先,左侧的5,就决定了,4为最大值的区间左边界不可能比5靠左;右侧的10也做出了同样的限制。所以4只能是自己这个区间的最大值。
- 那他又是多少区间的最小值呢,我们往左看,第一个小于4的值是3,所以5开始往右的位置可以做左边界;右边第一个小于4的值是2,所以10往左的位置可以做右边界。
- 假设当前值下标为i;左侧第一个小于该元素的下标为l,右侧为r。则以i为最小值的区间数量,通过组合计数原理,可以得到,为 ( i − l ) ∗ ( r − i ) (i-l)*(r-i) (i−l)∗(r−i)
而最小值怎么维护呢?我们用一个单调增栈即可,从左往右遍历,如果栈顶元素大于当前值,我们就出栈;直到栈顶元素小于当前值,这样我们就知道了小于当前值最近的左侧元素是在哪了。
右侧和最大值的计算过程类似。
还有一个小细节,就是数组中会有重复的元素;为了避免重复区间的计算,从左往右和从右往左的统计,我们需要分别用开区间和闭区间来表示。
class Solution {
public:
long long subArrayRanges(vector<int>& nums) {
int m = nums.size();
std::vector<int> lsmall(m, 0);
std::vector<int> rsmall(m, 0);
std::vector<int> llarge(m, 0);
std::vector<int> rlarge(m, 0);
std::stack<int> s; //从左往右单调增栈
// 从左往右单调增栈 不能出栈的时候栈顶就是当前元素左侧最近的小于当前元素的节点
s.push(-1);
for (int i = 0; i < m; ++i) {
while (s.top() != -1 && nums[s.top()] >= nums[i]) {
s.pop();
}
lsmall[i] = s.top();
s.push(i);
}
// 从右往左单调增栈 不能出栈的时候栈顶就是当前元素右侧最近的小于当前元素的节点
s = stack<int>();
s.push(m);
for (int i = m-1; i >= 0; i--) {
while (s.top() != m && nums[s.top()] > nums[i]) {
s.pop();
}
rsmall[i] = s.top();
s.push(i);
}
// 从左往右单调减栈 不能出栈的时候栈顶就是当前元素左侧最近的大于当前元素的节点
s = stack<int>();
s.push(-1);
for (int i = 0; i < m; i++) {
while (s.top() != -1 && nums[s.top()] <= nums[i]) {
s.pop();
}
llarge[i] = s.top();
s.push(i);
}
// 从右往左单调增栈 不能出栈的时候栈顶就是当前元素右侧最近的大于当前元素的节点
s = stack<int>();
s.push(m);
for (int i = m-1; i >= 0; i--) {
while (s.top() != m && nums[s.top()] < nums[i]) {
s.pop();
}
rlarge[i] = s.top();
s.push(i);
}
long long ans = 0;
for (int i = 0; i < m; ++i) {
ans += nums[i] * 1L * (i - llarge[i]) * (rlarge[i] - i);
ans -= nums[i] * 1L * (i - llarge[i]) * (rlarge[i] - i);
}
return ans;
}
};
边栏推荐
- Distinguish between i++ and ++i seconds
- After the college entrance examination, the following four situations will inevitably occur:
- Program.launch(xxx)打开文件
- Cobalt strike installation tutorial
- Using bindservice method to pause music playing
- Texture enhancement
- 高考之后,必然会出现以下四种情况:
- 明日考试 最后一天如何备考?二造考点攻略全整理
- Bi-sql between
- 修身励学篇
猜你喜欢

TC对象结构和简称

程序员:是花光积蓄在深圳买房?还是回到长沙过“富余”生活?

Bi-sql Union

Assembly language (4) function transfer parameters

Deep learning LSTM model for stock analysis and prediction

pbcms添加循环数字标签

4 years of working experience, and you can't tell the five communication modes between multithreads. Can you believe it?

4年工作经验,多线程间的5种通信方式都说不出来,你敢信?

Use redis' sorted set to make weekly hot Reviews

Bi-sql index
随机推荐
Powerbi - for you who are learning
Assembly language (3) 16 bit assembly basic framework and addition and subtraction loop
脱氧核糖核酸酶I中英文说明书
VB learning notes
汇编语言(4)函数传参
Picture rotation move zoom gradient
论文翻译 | RandLA-Net: Efficient Semantic Segmentation of Large-Scale Point Clouds
PHP 利用getid3 获取mp3、mp4、wav等媒体文件时长等数据
丹麥技術大學首創將量子計算應用於能源系統潮流建模
Reverse ordinal number by merge sort
Using macro code to generate handwriting automatically in word or WPS
Assembly language (4) function transfer parameters
Tencent cloud wecity Industry joint collaborative innovation to celebrate the New Year!
丹麦技术大学首创将量子计算应用于能源系统潮流建模
Boutique enterprise class powerbi application pipeline deployment
Redis persistence
How about compass stock trading software? Is it safe?
高考之后,必然会出现以下四种情况:
汇编语言(2)基础知识-debug
天书夜读笔记——反汇编引擎xde32