单调栈&单调队列

单调栈&单调队列

介绍

单调栈和单调队列是两种很简单,但是很强大的数据结构.一般不会直接出裸题,常常作为优化手段使用.(多见于dp)

单调队列实际上是升级版的单调栈.

单调栈

单调栈可以在O(n)时间复杂度下完成以下操作

对于给定的a[ ]数组,在O(n)时间内生成数组 L[ ],其中L[i]表示a[i] 左边/右边 第一个 小于/大于 a[i]的元素的下标(常记录下标,可以使得操作更灵活).

对于朴素算法(O(n^2))来说,这已经是一个非常大的优化了.

其思想就是维护栈的单调性(当然维护方法不唯一,具体情况具体分析,灵活运用)\

以(自栈顶到栈底)递增栈为例

第一种是如果当前想要插入的元素的值大于栈顶元素值,则弹出栈顶,继续比较,直到栈顶元素小于(也可能是小于等于,具体情况具体分析),或是栈为空,则插入(当然,插入之前的栈顶值就是L[i]的值)

第二种是如果当前想要插入的元素的值大于栈顶元素值,则不插入 (仅限于很特殊的题目,和这里的问题貌似不太相符合,以下我们只讨论第一种维护形式)

我们拿一个题举例子

HDU1506

题意

A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:
img
Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.

输入

The input contains several test cases. Each test case describes a histogram and starts with an integer n, denoting the number of rectangles it is composed of. You may assume that 1 <= n <= 100000. Then follow n integers h1, …, hn, where 0 <= hi <= 1000000000. These numbers denote the heights of the rectangles of the histogram in left-to-right order. The width of each rectangle is 1. A zero follows the input for the last test case.

输出

For each test case output on a single line the area of the largest rectangle in the specified histogram. Remember that this rectangle must be aligned at the common base line.

思路

这个题实际上有dp的解法,也有单调栈的解法,两种方法的思路都是枚举每个小矩形作为最后最大的矩形的顶部高度,就是遍历整个图形,假设当前的矩形就是最后的矩形的最高点,然后算出最大面积,然后最后取所有答案中的最大值即可.

算法正确性显然.我们使用两个数组,L[ ],R[ ],L[i]表示如果第i个矩形是顶峰,则其构成的最大矩形的最左侧的矩形的下标,R[ ]表示其右侧的下标,最后矩形的面积就是
max ⁡ i n − 1 [ ( R [ i ] − L [ i ] + 1 ) ∗ a [ i ] ] \max_i^{n-1}[(R[i]-L[i]+1)*a[i]] imaxn1[(R[i]L[i]+1)a[i]]

我们先讨论L[ ]的求解方法.L[i]的值实际上是第i个矩阵左侧第一个比它矮的矩阵的下标+1

我们就考虑用单调栈解决此问题

for(int i=0; i<n; ++i) {
   
    while(!s.empty()&&a[s.top()]>=a[i]) {
   
        s.pop();
    }
    if(s.empty()) {
   
        l[i] = 0;  // 其左边的元素都比它大,则左边界就是第一个矩阵
    } else {
   
        l[i] = s.top()+1; // 左侧第一个比它矮的矩阵的下标+1
    }
    s.push(i); // 记录下标比记录值要灵活
}

同理我们再对R[ ] 如法炮制,也可以在O(n)时间内解决

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[100000+100];
int l[100000+100];
int r[100000+100];
int main() {
   
    int n;
    while(cin>>n,n) {
   
        stack<int> s;
        stack<int> s2;
        for(int i=0; i<n; ++i) {
   
            cin>>a[i];
        }
        for(int i=0; i<n; ++i) {
   
            while(!s.empty()&&a[s.top()]>=a[i]) {
   
                s.pop();
            }
            if(s.empty()) {
   
                l[i] = 0;
            } else {
   
                l[i] = s.top()+1;
            }
            s.push(i);
        }
        for(int i=n-1; i>=0; --i) {
   
            while(!s2.empty()&&a[s2.top()]>=a[i]) {
   
                s2.pop();
            }
            if(s2
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值