
柱状图最大矩形的单调栈解法
在面对一组柱子高度时,为什么不直接暴力枚举每个矩形,而是常常推荐使用单调栈?这种方法相比普通遍历能带来什么优势?
单调栈能高效定位每根柱子的边界
单调栈的核心价值在于,它可以帮助我们快速找到每根柱子左侧和右侧第一个比它更矮的柱子,从而确定该柱子能扩展的最大宽度。暴力做法需要反复检查区间,时间开销较大;单调栈通过维护一个高度递增的栈,在柱子高度出现下降时及时结算面积,整体效率更高,通常可以把时间复杂度降低到 O(n)。
当我们看到单调栈解法时,经常会发现代码里维护了一个栈,但不太清楚栈中存的是高度还是下标。这个设计背后的目的是什么?
栈中通常保存下标,便于计算宽度
在柱状图最大矩形问题中,单调栈里一般保存的是柱子的下标,而不是直接保存高度。这样做的原因是,矩形面积不仅取决于高度,还取决于宽度;只有下标才能方便计算左右边界之间的距离。借助下标,程序可以在遇到更矮柱子时快速计算以当前柱子为高的矩形面积,避免重复扫描区间。
很多单调栈代码会在遇到当前柱子比栈顶柱子更矮时,立刻弹栈并计算面积。这个时机为什么是正确的,难道不会漏掉更大的矩形吗?
更矮柱子出现时,说明栈顶柱子的扩展范围已经确定
当遍历到一根更矮的柱子时,意味着栈顶那根更高柱子向右扩展的边界已经被找到,也就是当前下标位置。由于栈内保持递增,栈顶柱子向左的边界也早已由前一个更矮柱子确定,因此它能够形成的最大宽度已经明确。这个时机结算面积不会遗漏更优解,因为每根柱子的最大可能矩形都会在其右边界首次被阻断时被完整计算。
遇到一段高度相同的柱子时,单调栈的弹栈和入栈规则是否需要特别调整?是否会影响最大矩形的结果?
相同高度可以按统一规则入栈,关键是保证边界计算一致
连续相同高度的柱子并不会改变问题本质,但会影响代码处理方式。常见做法是将相同高度视作一种统一情况,按照固定规则决定是否保留较早的下标,或在弹栈时统一处理等高元素。只要保证左边界和右边界的计算一致,就不会影响最大矩形结果。实际写代码时,重点是避免重复计算和边界混乱。
如果同样是求柱状图中的最大矩形,单调栈和分治法都能做,那么在面试、竞赛或工程实现里,哪种方式更常用?
单调栈更简洁高效,适合大多数实际场景
分治法也可以求解,但实现通常更复杂,且在某些情况下容易退化。单调栈的优势在于思路直接、代码长度适中、时间复杂度稳定,适合面试和竞赛中的快速实现,也更适合处理大规模输入。若目标是高效、稳定地求出答案,单调栈通常是更优先的选择。