刷题笔记:力扣第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)。

相关推荐
青少儿编程课堂2 小时前
威佐夫博弈(双堆取子游戏)解析
c++·python·算法·bfs·信息学竞赛
辰烨chenye6 小时前
LeetCode Hot 100 题解 · 普通数组篇
算法·leetcode·职场和发展
一米阳光86619 小时前
软考高级【信息系统项目管理师】高项重要考点(3)高级项目管理-下 助你顺利上岸!
笔记·职场发展·软考·信息系统项目管理师·高级职称
hqyjzsb9 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
辰烨chenye9 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
微功夫信息技术9 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划
dianziyao_10 小时前
第 4.1 篇:让 Codex 理解你的双链——AI 辅助发现笔记间的关联
人工智能·笔记
sanjiaomao33310 小时前
从论文公式到Python实现:用单元测试校验滑动平均算法
python·算法·单元测试
乐迪信息10 小时前
如何通过AI防爆摄像机精准判断船舶超速?
大数据·人工智能·算法·安全·目标跟踪