19.15 开始回忆单调栈
因为单调栈 已经很熟悉了,就没有继续听下去。
对于这样一个数组,
在往里面放5的时候,改变了 从上到下依次为 从大到小的事实
所以需要弹出
生成这两个数后,弹出
下标压在一起
根据一棵数组,如何创建一棵树
例子:对于这样一个数组
创建的数,可以是这个样子
也可以是这个样子:
法一:可以先建立大根堆,然后重连,串出整棵树。
复杂度O(N)
法二:根据单调栈,得到这么些信息
对于5这种,左右均无的,就是头结点
对于3,弄到4的底下
对于2,左右那个小,挂在那个下面
最后结果:
证明该流程是否要对:
1.该方法可以生成二叉树,而不是多叉树
该流程就是讲一个节点 如何找它的父。
证明a,不可能有三个及以上孩子
证a在任意一侧,最多只会有一个树 挂在其下方
反证:b,c都挂在了a的底下,会发生什么情况。
得到结论
又因为数组中没有重复值,所以b和c一定可以分出大小
若b>c,而b是离c更近的,那为什么c要选a作为父呢?根据流程,c会选b作为父
所以矛盾
若b<c,且c<a,c是最大数中,较小的一个,所以b会找c作为父,第二种情况也不成立
2.生成一个数,而不是多棵树
数组中没有重复的数,最大值作为的头结点一定是唯一的,
求最大子矩阵大小
看高度为4的直方图,向左右能扩到什么程度
同理,看高度为3的直方图,向左右能扩到什么程度
下面看怎么使用单调栈解决这个问题:
之前的单调栈解决的是,找到左右两边最近的最大值,所以由下到上,必须满足从大到小
现在我们解决的是,找到左右两边最近的最小值,
所以由下到上,必须满足从小到大,如下所示。
当3准备进入时,违背了这个准则,于是4要生成信息并弹出
此时3在栈内部,2准备进入
3生成信息并弹出
之后剩下的数进入:
6是自己出来的,所以,右边界是其不可到达的
6下面是5,所以,3位置是其不可到达 的
5是自己出来的,所以右边界是其不可到达的
5下面是2,所以,2位置是其不可到达 的
所以,除了2和5位置,其余位置3 4均可到达
所以,5位置可扩10个数
相等的时候会发生什么?
再举个例子:
对于这样一个数:
画成柱状图的形式:
4 得到矩阵为4的规模
对于大小一样的数,位置进行压缩。
原始问题,在整个正方形中,找到最大的正方形大小。
先求必须以第0行打底的 所有长方形中,最大的长方形面积
即把1 0 1 1视为一个直方图处理
再求必须以第1行 打底的 所有长方形中,最大的长方形面积
即第一行和第二行相加的,
得到2 1 2 2
各表示,以当前位置为底,之前有多少个连续的1。
再求必须以第2行 打底的 所有长方形中,最大的长方形面积
得到 3 2 3 0
注意最后一个,本身是0,所以往上连续是1的数,为0
这种算法求矩阵的算法复杂度为O(N×M),
而矩阵本身就是N×M大小的,
所以,算法复杂度很低, 相当于遍历一遍就求出了
代码解析:
数组中没有数,自然是0
准备一个栈, 名字为stack
这个for循环遍历数组中的每一个数,
当栈不等于空,并且当前数i 小于等于栈顶 的值。
第一个数进入时,直接压进去第一个数
当while条件满足时,
弹出栈的当前位置
例如。3小于4,弹出0位置。
k是 左边界
如果弹出之后,栈是空的,则左边界为-1,
否则就是 弹出之后的 栈顶。
i是当前数,也为有边界
所以中间有多少个数呢?i-k-1个!
知道左右边界,就知道可以扩充的区域!
如下,向左向右扩了多少个格子 乘以 当前值(高度)
所以,curArea就是 要出去的下标,以其作为高,能扩充的范围
我们始终在找全局最大值,
下面讲底下这个while。
我们再遍历每一个数的时候,会有东西从栈中出来。但是栈中总会剩余东西!
下面这部分就是结算while中剩下的东西。
还是弹出j位置。
如果,栈已经空了,左边界为-1,否则底下的位置便是我的左边界。
此时,有边界统一是 数组的右边。
01.22.00
这是本题的主函数: