刷题笔记:力扣第84题-柱状图中最大的矩形

1.本题和力扣第42题-接雨水的单调栈方法是遥相呼应的,那道题目是使用递增单调栈,寻找凹槽,本道题就是使用递减单调栈,寻找凸起。

2.一开始的想法如下:

(1)遍历一遍数组,每次都将存储的结果与当前元素大小比较,避免出现元素本身形成矩形即为答案的情况。

(2)先寻找两边低中间高的凸起结构,处理方式类似于接雨水题目,矩形宽度w等于当前下标i减去栈顶下标,计算的时候需要考虑两种情况:较高边为高还是较低边为高。若较高边为高,宽度应为w -- 1,;若较低边为高,宽度即为w。

(3)遍历完一遍数组后,处理剩余的栈内元素,此时栈内元素一定是非递增的,所以依次算出所有可能的矩形面积后与结果值进行比较即可。

3.基于以上思想,写出的完整代码如下:

cpp 复制代码
 1. int largestRectangleArea(int* heights, int heightsSize) {
 2.     int stack[100001];
 3.     int top = 0;
 4.     int res = 0;
 5.  
 6.     for (int i = 0; i < heightsSize; i++){
 7.         res = fmax(res, heights[i]);
 8.         while (top >= 1 && heights[stack[top - 1]] > heights[i]){
 9.             top--;
10.             if (top >= 1){
11.                 int w = i - stack[top - 1] + 1;
12.                 int res1 = fmin(heights[i], heights[stack[top - 1]]) * w;
13.                 int res2 = fmax(heights[i], heights[stack[top - 1]]) * (w - 1);
14.                 int res_tmp = fmax(res1, res2);
15.                 res = fmax(res, res_tmp);
16.             }
17.         }
18.         stack[top++] = i;
19.     }
20.  
21.     for (int i = 0; i < top; i++){
22.         res = fmax(res, heights[stack[i]] * (top - i));
23.     }
24.  
25.     return res;
26. }

本地测试通过了,但是提交后出错了:

经过检查,发现自己处理栈内剩余元素的逻辑是错误的,虽然剩余元素确实是非递增的,但是最终的答案可能贯穿了已经出栈的元素和栈内剩余元素。比如该测试用例中,元素1就是如此,最终答案应该是1贯穿了全部元素,答案为1*3=3。

4.本题使用递减单调栈的核心思想没有错,但代码实现逻辑有问题,本题应该是通过遍历数组来求中间凸起部分的最大面积,而不是带上两边的最大面积,这样会导致情况复杂且最后无法处理剩余栈元素。且本题需要引入虚拟节点的思想,在数组首尾各加一个虚拟的0,首部的0可以处理栈空的情况,此时矩形宽度就是当前元素的下标;尾部的0可以处理最后栈有剩余的情况,强制所有元素出栈。

5.基于以上思想,可写出完整代码如下:

cpp 复制代码
 1. int largestRectangleArea(int* heights, int heightsSize) {
 2.     // 单调栈,存储柱子下标,栈内下标对应的高度保持单调递增
 3.     int stack[100001];
 4.     // top=0 代表栈为空
 5.     int top = 0;
 6.     // 记录最大矩形面积
 7.     int res = 0;
 8.     // 遍历到 i == heightsSize 时,cur_h置0,相当于在数组末尾追加一根高度为0的柱子,用来强制弹出栈中剩余所有元素
 9.     for (int i = 0; i <= heightsSize; i++){
10.         // 到达数组末尾,当前高度取0;否则取heights[i]
11.         int cur_h = (i == heightsSize) ? 0 : heights[i];
12.         // 栈不为空,且栈顶柱子高度大于当前高度,说明找到栈顶柱子的右边界
13.         while (top >= 1 && heights[stack[top - 1]] > cur_h){
14.             // 取出要计算面积的柱子高度
15.             int h = heights[stack[top - 1]];
16.             // 弹出栈顶下标
17.             top--;
18.             
19.             // 宽度:栈空说明左侧没有比它更小的柱子,宽度就是i;否则宽度=当前i - 新栈顶下标 -1
20.             int w = (top == 0) ? i : (i - stack[top - 1] - 1);
21.             int area = h * w;
22.             // 更新最大面积
23.             res = fmax(res, area);
24.         }
25.         // 当前下标入栈,维持单调递增栈
26.         stack[top++] = i;
27.     }
28.     return res;
29. }

该算法时间复杂度和空间复杂度均为O(n)。

相关推荐
马可家的菠萝1 分钟前
个人知识库怎么建?从一个正在学的技术主题开始
前端·笔记·知识管理·个人知识库
碧海银沙音频科技研究院10 分钟前
基于ATS308X的无线语音交互对话功能实现
人工智能·嵌入式硬件·深度学习·算法
ss27311 分钟前
AI时代首先数据库-PostgreSQL实战笔记 | 17 PostgreSQL SQL高级查询:窗口函数、CASE、COALESCE
数据库·笔记·postgresql
叶子丶苏12 分钟前
提示词工程格式四段式与少样本-VibeCoding入门笔记06
人工智能·笔记
尹玉玺1 小时前
从原子残片到天道公理:以德谟克利特思想全貌,重新定界西方唯物认知的历史层级与边界
人工智能·算法·架构
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:差分数组与区间修改实战解析
c++·python·算法·bfs·信息学竞赛
问心无愧05131 小时前
[极客大挑战 2019]HardSQL
笔记
m0_646429971 小时前
BCrypt 与 JWT 认证流程学习笔记
笔记·学习
重生之小比特1 小时前
【算法拾光】二分查找|二分查找 + 再排序数组中查找元素的第一个和最后一个位置
算法·leetcode·职场和发展
文丑颜不良啊1 小时前
LeetCode76~100题目解析
java·leetcode