

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)。