迈向光明之路,注定荆棘丛生
单调队列、单调栈
一、单调队列:
(一)概念及作用:
维护区间的最大值(最小值),单调队列本质上是一个单调递减(单调递增)序列。
(二)维护演示:
下面,在一个数组中以区间为三,我们维护一个单调递减的单调队列。
(三)代码演示:
int main() {
int n, k;
scanf("%d%d", &n, &k);
vector<int> arr;
deque<int> q;
for (int i = 0, a; i < n; i++)
{
scanf("%d", &a);
arr.push_back(a);
}
output(arr);
for (int i = 0; i < n; i++) {
while (!empty(q) && arr[q.back()] > arr[i]) {
q.pop_back();
}
q.push_back(i);
if (i - q.front() == k) q.pop_front();
printf("[%d, %d] : min = %d\n", max(i - k + 1, 0), i, arr[q.front()]);
}
return 0;
}
(四)例题剖析:
剖析:
首先求区间和,我们需要构建前缀和数组,依次遍历前缀和数组元素的每个值,以M为3举例,维护一个长度为3的单调队列。
例如,当遍历到数组下标6时,用当前元素120减去矩形区域的最小值就得到当前元素的最大和。遍历完整个数组,得到最大值。
代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
int main() {
int n, m;
scanf("%d%d", &n, &m);
vector<int> v( n + 1);
deque<int> q;
v.push_back(0);
for (int i = 1; i <= n; i++) {
scanf("%d", &v[i]);
v[i] += v[i - 1];
}
int ans = 0;
q.push_front(0);
for (int i = 1; i <= n; i++) {
ans = max(ans, v[i] - v[q.front()]);
while (!q.empty() && v[q.back()] > v[i]) q.pop_back();
q.push_back(i);
if (i - q.front() == m) q.pop_front();
}
printf("%d", ans);
return 0;
}
二、单调栈:
(一)概念及作用:
维护距离当前元素最近的最大值(最小值),单调队列本质上是一个单调递减(单调递增)序列。
(二)维护演示:
相比于单调队列,单调栈在维护时不需要维护头部出元素,相对比较简洁。
(三)代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stack>
#include<vector>
using namespace std;
int main() {
int n, k;
scanf("%d%d", &n, &k);
vector<int> arr;
stack<int> s;
vector<int> lmin(n + 1), rmin(n + 1);
arr.push_back(-1);
for (int i = 0, a; i < n; i++)
{
scanf("%d", &a);
arr.push_back(a);
}
arr.push_back(-1);
for (int i = 0; i < n; i++) {
while (!s.empty() && arr[s.top()] > arr[i]) {
rmin[s.top()] = i;
s.pop();
}
s.push(i);
}
while (!s.empty()) s.pop();
for (int i = n - 1; i >= 0; i--) {
while (!s.empty() && arr[s.top()] > arr[i]) {
lmin[s.top()] = i;
s.pop();
}
s.push(i);
}
printf(" ");
for (auto x : lmin) printf("%3d", x); printf("\n");
for (auto x : rmin) printf("%3d", x); printf("\n");
for (int i = 1; i <= n; i++) {
printf("arr[%d] = [%d, %d]\n", i, arr[lmin[i]], arr[rmin[i]]);
}
return 0;
}
(四)例题剖析:
代码演示:
class Solution {
public:
int trap(vector<int>& height) {
int ans = 0, n = height.size();
stack<int> s;
for(int i = 0; i < n; i++){
while(!s.empty() && height[s.top()] <= height[i]){
int height_pre = height[s.top()];
s.pop();
if(s.empty()) break;
ans += (min(height[i], height[s.top()]) - height_pre) * (i - s.top() - 1);
}
s.push(i);
}
return ans;
}
};
三、结束语:
单调队列和单调栈是一种求最值的高效的数据结构,其中形式上类似单调函数。接下来小编会继续更新数据结构的知识,希望和大家一起学习,大家支持一下吧!