算法打卡day52|单调栈篇03| 84.柱状图中最大的矩形

算法题

Leetcode 84.柱状图中最大的矩形

题目链接:84.柱状图中最大的矩形

大佬视频讲解:84.柱状图中最大的矩形视频讲解

个人思路

这题和接雨水是相似的题目,原理上基本相同,也是可以用双指针和单调栈解决,只是有些细节不同。

解法
双指针

相比接雨水,这道题难在要记录每个柱子 左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度。所以需要循环查找,其他思路与接雨水一样。

java 复制代码
class Solution {
    public int largestRectangleArea(int[] heights) {
        int length = heights.length;
        int[] minLeftIndex = new int [length];
        int[] minRightIndex = new int [length];
        
        minLeftIndex[0] = -1 ;// 记录左边第一个小于该柱子的下标
        for (int i = 1; i < length; i++) {
            int t = i - 1;
            // 这里用while来不断向右寻找
            while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
            minLeftIndex[i] = t;
        }

        // 记录每个柱子右边第一个小于该柱子的下标
        minRightIndex[length - 1] = length;
        for (int i = length - 2; i >= 0; i--) {
            int t = i + 1;
            while(t < length && heights[t] >= heights[i]) t = minRightIndex[t];
            minRightIndex[i] = t;
        }

        
        int result = 0;
        for (int i = 0; i < length; i++) {// 求和
            int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);
            result = Math.max(sum, result);
        }
        return result;
    }
}

时间复杂度:O( n**)**;( 每个元素都执行了最多n次的比较操作)

空间复杂度:O( n**);** (minLeftIndex和minRightIndex暂存数据)


单调栈

本地单调栈的解法和接雨水的题目是类似的,接雨水是找每个柱子左右两边第一个大于该柱子高度的柱子 ,而本题是找每个柱子左右两边第一个小于该柱子的柱子。

**所以这道题的单调栈里的顺序,**应该是从大到小的顺序!

来举一个例子,如图:

​

只有栈里从大到小的顺序,**才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。**所以本题单调栈的顺序正好与接雨水反过来。

此时应该可以发现其实就是栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度

除了栈内元素顺序和接雨水不同,剩下的逻辑都差不多,代码如下

主要分析清楚如下三种情况:

  • 情况一:当前遍历的元素heightsi大于栈顶元素heightsst.top()的情况
  • 情况二:当前遍历的元素heightsi等于栈顶元素heightsst.top()的情况
  • 情况三:当前遍历的元素heightsi小于栈顶元素heightsst.top()的情况

除此之外,height数组前后需要各加一个元素0,解释如下:

末尾需要要加元素0 ,因为如果数组本身就是升序的,例如2,4,6,8,那么入栈之后 都是单调递减,一直都没有走, 情况三 计算结果的哪一步,所以最后输出的就是0了。那么结尾加一个0,就会让栈里的所有元素,走到情况三的逻辑。 如图:

​

开头也要加元素0, 因为如果数组本身是降序的,例如 8,6,4,2,在 8 入栈后,6 开始与8 进行比较,此时得到 mid(8),rigt(6),但是得不到 left。因为 将 8 弹出之后,栈里没有元素了,那么为了避免空栈取值,直接跳过了计算结果的逻辑。之后又将6 加入栈(此时8已经弹出了),然后 就是 4 与 栈口元素 8 进行比较,周而复始,那么计算的最后结果resutl就是0。 如图所示:

​

java 复制代码
class Solution {
    int largestRectangleArea(int[] heights) {
        Stack<Integer> st = new Stack<Integer>();
        
        // 数组扩容,在头和尾各加入一个元素
        int [] newHeights = new int[heights.length + 2];
        newHeights[0] = 0;
        newHeights[newHeights.length - 1] = 0;
        for (int index = 0; index < heights.length; index++){
            newHeights[index + 1] = heights[index];
        }

        heights = newHeights;
        
        st.push(0);
        int result = 0;

        // 第一个元素已经入栈,从下标1开始
        for (int i = 1; i < heights.length; i++) {
            // 注意heights[i] 是和heights[st.top()] 比较 ,st.top()是下标
            if (heights[i] > heights[st.peek()]) {
                st.push(i);
            } else if (heights[i] == heights[st.peek()]) {
                st.pop();
                st.push(i);
            } else {
                while (heights[i] < heights[st.peek()]) { //循环比较
                    int mid = st.peek();
                    st.pop();
                    int left = st.peek();
                    int right = i;
                    int w = right - left - 1;
                    int h = heights[mid];
                    result = Math.max(result, w * h);
                }
                st.push(i);
            }
        }
        return result;
    }
}

时间复杂度:O( n**)**;( 每个元素最多被栈操作处理一次,且整个数组会被完全遍历一次)

空间复杂度:O( n**);**(扩容数组)


以上是个人的思考反思与总结 ,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网

相关推荐
m4Rk_5 小时前
【论文阅读】Agent 记忆机制(83):Inside Out——用可演化 PersonaTree 构建 Agent 的核心长期记忆
论文阅读·人工智能·学习·开源·github
不会就选b5 小时前
算法日常・每日刷题--<贪心>25
数据结构·算法
EatFan5 小时前
Spring Boot 4 落地观察:从 yudao-cloud、matecloud、JPower 看国产脚手架的升级路线与迁移清单
java·spring boot·后端·spring cloud·微服务·后端开发·jdk 21
Maiko Star6 小时前
* LangChain 提示词模板详解:ChatPromptTemplate 的使用与高级特性
java·人工智能·langchain
鬓戈6 小时前
Rust 语言与 AI 应用生态调研及学习路径
人工智能·学习·rust
传奇开心果编程6 小时前
【SwiftUI娓娓道来】第3课:让界面活起来——交互与动画指南
学习·macos·ui·ios·swiftui·swift
xian_wwq6 小时前
【学习笔记】等保合规安全基线核查实战
笔记·学习
传奇开心果编程7 小时前
【Jetpack Compose进阶学与练】第14课:系列收尾复习总结;Compose项目常见坑点汇总;学习路线与后续学习方向
android·学习·ui·kotlin·android jetpack
西部驯兽师7 小时前
制造企业的信息化选型课题(一)
职场和发展
yangmu32037 小时前
发动机是怎么把油变成动力的:四冲程内燃机原理拆解
学习