当前位置: 首页 > news >正文

从零开始写算法-栈-柱状图中最大的矩形

一、题目描述

题目来源:LeetCode 84. Largest Rectangle in Histogram

给定 n 个非负整数,表示直方图的柱状高度。
每个柱子的宽度为 1,求能形成的最大矩形面积。

示例:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大矩形面积是由高度 5 和 6 构成的矩形(宽度为 2)。

二、思路分析

这个题看起来像简单的“找最大面积”,但其实是典型的 单调栈应用题

我们需要为每个柱子找到:

  • 它左边第一个比它矮的柱子;

  • 它右边第一个比它矮的柱子。

这样,它所能扩展的最大矩形就确定了。


直观解释

假设我们有一组高度:[2, 1, 5, 6, 2, 3]

我们从左往右遍历,用一个 单调递增栈(存下标) 维护柱子的高度顺序:

  • 当当前柱子比栈顶“高”时,说明还可以往右延伸,入栈。

  • 当当前柱子比栈顶“矮”时,说明栈顶那根柱子的“右边界”已经确定——此时就可以计算它的面积。

换句话说:

入栈延迟计算,出栈触发计算。

三、核心逻辑讲解

我们维护一个递增栈 st,存放的是柱子的下标:

  1. heights[i] >= heights[st.top()] 时 —— 入栈

  2. heights[i] < heights[st.top()] 时 ——
    说明栈顶柱子的右边界被确定了,此时:

    • 弹出栈顶下标 idx

    • 此柱子的高度是 heights[idx]

    • 弹出后的栈顶是“左边第一个比它矮的柱子”;

    • 当前 i 是“右边第一个比它矮的柱子”;

    • 所以矩形的宽度 = i - st.top() - 1

    • 面积 = heights[idx] * width

  3. 遍历结束后,为了清空栈中的剩余柱子,我们可以在数组末尾添加一个哨兵 -1


四、代码实现(cpp)

class Solution {
public:int largestRectangleArea(vector<int>& heights) {// 思路:// 暴力解法:对每个柱子,向左右扫描找到第一个比它矮的柱子,确定宽度后计算面积。时间复杂度 O(n^2)。// 优化1:可以用两个数组或栈,分别预处理出每个柱子左边第一个更矮的位置和右边第一个更矮的位置,从而在 O(n) 时间内计算出所有面积。// 优化2(最终方案):使用单调递增栈,只遍历一次,通过“出栈时计算面积”的方式同时确定左右边界,时间复杂度降为 O(n),空间 O(n)。/*•	idx:是 当前出栈的柱子的下标。•	heights[idx]:就是该柱子的高度(矩形高度)。•	i:是右边第一个比它矮的柱子的下标(右边界)。•	left:是左边第一个比它矮的柱子的下标(左边界)。•	(i - left - 1):就是该矩形的宽度。•	栈中存的是下标(index)•	栈中对应的高度是单调递增的(从栈底到栈顶)•	每次遇到“比栈顶矮”的柱子时,就说明我们找到了栈顶柱子的「右边第一个比它矮」的位置。*/stack<int> st;int n = heights.size();heights.push_back(-1); // 目的是为了最后清空栈,执行所有的遍历,因为只有在“当前柱子比栈顶柱子矮”时,才会触发出栈计算面积。int ans = 0;for (int i = 0; i <= n; ++i) {while (!st.empty() && heights[i] < heights[st.top()]){ // 确保栈是递增的,且栈顶要比我当前这个高度小int idx = st.top();st.pop();int left = st.empty()? -1 : st.top();ans = max(ans, (i - left - 1) * heights[idx]); // 注意:我们在这里不是在计算「当前柱子 i」的面积,而是在计算「被弹出的柱子 idx」能延伸的最大矩形面积。}st.push(i);}return ans;}
};

五、举例说明(关键理解点)

heights = [2,1,5,6,2,3] 为例:

步骤当前 i,h栈内容弹出面积计算当前最大面积
i=0,h=2入栈[0]--0
i=1,h=11 < 2 → 弹出0[ ]idx=0(i - (-1) -1)*2=22
i=1,h=1入栈[1]--2
i=2,h=5入栈[1,2]--2
i=3,h=6入栈[1,2,3]--2
i=4,h=22<6 弹出3[1,2]idx=3(4-2-1)*6=66
i=4,h=22<5 弹出2[1]idx=2(4-1-1)*5=1010 ✅
i=4,h=2入栈[1,4]--10
i=5,h=3入栈[1,4,5]--10
i=6,h=-1触发清栈弹出5,4,1...-...10

最终最大面积 = 10


六、关键点总结

为什么要加一个 -1

  • 为了强制让栈里的柱子全部弹出,计算剩余面积。

为什么要乘的是 heights[idx] 而不是当前的?

  • 因为当前柱子是“右边界”,被弹出的才是“矩形高度的主体”。

为什么在弹出时计算面积?

  • 弹出时说明边界确定了,矩形的左右范围都清楚,正是计算的最佳时机。


七、单调栈通用思维模型

单调栈思想:维持有序,弹出计算。

常见应用:

题目类型栈顺序计算时机
柱状图最大矩形单调递增弹出时计算面积
每日温度单调递减弹出时计算间隔
下一个更大元素单调递减弹出时确定答案

八、总结一句话记忆:

单调栈的精髓是:
「入栈延迟计算,出栈触发计算」
只要掌握这个节奏,柱状图类题目再也不怕!

http://www.dtcms.com/a/585616.html

相关文章:

  • Flova.ai实战:AI视频创作平台的开发与应用指南
  • 网站推广是什么岗位济南建站网站
  • SEO入门
  • 异腾910B NPU实战:vLLM模型性能优化深度指南
  • 移动网站备案微信里的小程序占内存吗
  • easy_RSA(攻防世界)
  • 「JAVA 入门」JDK概念及作用 | JDK 的下载及安装 | 自动和手动配置环境变量 | 编译Java文件 | 运行class文件
  • AIGC首帧图尾帧图生成视频案例教程
  • Go语言流程控制
  • wix建设网站商品图片网站开发
  • 【AI-agent】LangChain开发智能体工具流程
  • 测量为什么要建站本地广东中山网站建设
  • 数据结构与算法:树上倍增与LCA
  • P1997 faebdc 的烦恼+P7764 [COCI 2016/2017 #5] Poklon(莫队)
  • Nginx请求超时
  • 基于单片机的交流功率测量仪设计与实现
  • Zookeeper实现分布式锁
  • 好看的个人网站设计专做轮胎的网站
  • VGG论文精细解读
  • 抖音自动化-实现给特定用户发私信
  • 安徽省教育基本建设学会网站查看网站被百度收录
  • LeetCode算法学习之旋转数组
  • webrtc降噪-NoiseSuppressor类源码分析与算法原理
  • openEuler容器化实践:从Docker入门到生产部署
  • Spring Security实战代码详解
  • ES6 Promise:告别回调地狱的异步编程革命
  • 企业网站备案教程免费建设网站抽取佣金
  • seo网站诊断流程公司网站建设费用会计处理
  • 与Figma AI对话的对话框在哪里?
  • 【科研绘图系列】R语言绘制微生物箱线图(box plot)