最近在做题目的时候,发现了一种很好的数据结构:单调栈和单调队列
栈和队列的应用
单调栈
以前自己对栈的认识紧限于陷入后出的数据结构,实现一个逆序输出。直至遇到了这道题目,让我对栈有了重新的认识。
题目如下:
给出一个柱形统计图(histogram),它的每个bar的宽度为1,现在需求出柱形图中所能组成的矩形的最大面积。例如:6 2 1 5 6 2 3 ,其中7代表统计图中的bar的个数,后面的数据分别表示每个bar的高度。
先说一下自己难道题目的第一反应,分别计算出每个高度可以向左和向右扩展的长度,然后计算出每个高度对应的矩形的面积,得到最大值。显然这是一个$O(n^2)$复杂度的算法。
那么有没有更简单的算法了:当然有,单调栈
先介绍以下单调栈的执行过程:
从第一个bar开始往后扫描,扫描过程满足以下规则
(1)如果全部元素入栈,则将栈弹空;
(2)如果当前的bar的高度大于栈顶bar的高度,则将当前bar的下标入栈;
(3)否则执行出栈操作,直到栈顶的元素小于当前要入栈的元素,记录弹出下标对应的bar的高度,并计算出一个面积,比较这个面积与当前的最大面积,最后得到最大面积。
栈中的保存的元素为(高度,起始的索引号)
算法的执行过程为:
- 初始化时,栈底的元素为(0,0),i = 1,面积s = 0,上一次的高度lastHeight = 0;
- 此时 i = 1,加入第一个元素(2,1),满足条件(1),故入栈,栈中的元素为(0,0),(2,1);
- i=2 ,加入第二个元素(1,2),满足条件(2),将要出栈,$面积 = (i-startindex)height$,计算出的面积为 s = 2,lastHeight = 2 > 1,将(1,1)入栈,*栈中的元素为(0,0), (1,1);
- i = 3 (5,3),入栈栈中的元素为(0,0), (1,1),(5,3);
- i = 4 (6,4),入栈栈中的元素为(0,0), (1,1),(5,3),(6,4);
- i = 5 (2,5),出栈,(6,4)出栈计算面积$s_1 = (5-4)6 = 6$,(5,3)出栈$s_1 = (5-3)5 = 10$,到(1,1)时, 1 < 2,故将(2,3)入栈,此时的元素为(0,0),(1,1),(2,3);
- i = 6, (3,6),入栈,此时全部入栈,将栈弹空;
具体实现的代码为:
1 |
|
单调队列
1 |
|