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


      算法题

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

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

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

     个人思路 

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

    解法
    双指针

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

    1. class Solution {
    2. public int largestRectangleArea(int[] heights) {
    3. int length = heights.length;
    4. int[] minLeftIndex = new int [length];
    5. int[] minRightIndex = new int [length];
    6. minLeftIndex[0] = -1 ;// 记录左边第一个小于该柱子的下标
    7. for (int i = 1; i < length; i++) {
    8. int t = i - 1;
    9. // 这里用while来不断向右寻找
    10. while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
    11. minLeftIndex[i] = t;
    12. }
    13. // 记录每个柱子右边第一个小于该柱子的下标
    14. minRightIndex[length - 1] = length;
    15. for (int i = length - 2; i >= 0; i--) {
    16. int t = i + 1;
    17. while(t < length && heights[t] >= heights[i]) t = minRightIndex[t];
    18. minRightIndex[i] = t;
    19. }
    20. int result = 0;
    21. for (int i = 0; i < length; i++) {// 求和
    22. int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);
    23. result = Math.max(sum, result);
    24. }
    25. return result;
    26. }
    27. }

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

    空间复杂度:O( n);minLeftIndexminRightIndex暂存数据)


    单调栈

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

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

    来举一个例子,如图:

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

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

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

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

    • 情况一:当前遍历的元素heights[i]大于栈顶元素heights[st.top()]的情况
    • 情况二:当前遍历的元素heights[i]等于栈顶元素heights[st.top()]的情况
    • 情况三:当前遍历的元素heights[i]小于栈顶元素heights[st.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。 如图所示:

    1. class Solution {
    2. int largestRectangleArea(int[] heights) {
    3. Stack st = new Stack();
    4. // 数组扩容,在头和尾各加入一个元素
    5. int [] newHeights = new int[heights.length + 2];
    6. newHeights[0] = 0;
    7. newHeights[newHeights.length - 1] = 0;
    8. for (int index = 0; index < heights.length; index++){
    9. newHeights[index + 1] = heights[index];
    10. }
    11. heights = newHeights;
    12. st.push(0);
    13. int result = 0;
    14. // 第一个元素已经入栈,从下标1开始
    15. for (int i = 1; i < heights.length; i++) {
    16. // 注意heights[i] 是和heights[st.top()] 比较 ,st.top()是下标
    17. if (heights[i] > heights[st.peek()]) {
    18. st.push(i);
    19. } else if (heights[i] == heights[st.peek()]) {
    20. st.pop();
    21. st.push(i);
    22. } else {
    23. while (heights[i] < heights[st.peek()]) { //循环比较
    24. int mid = st.peek();
    25. st.pop();
    26. int left = st.peek();
    27. int right = i;
    28. int w = right - left - 1;
    29. int h = heights[mid];
    30. result = Math.max(result, w * h);
    31. }
    32. st.push(i);
    33. }
    34. }
    35. return result;
    36. }
    37. }

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

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


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

  • 相关阅读:
    吉利发布新出行科技品牌“礼帽出行” 定位高品质定制化出行
    为什么做ACL标准配置主机与其他三台ping不通
    java项目-第137期jsp+servlet的周公算命预测系统-java毕业设计
    java 中int与Integer的区别
    pandas将多个Series对象当成数据行进行垂直合并形成dataframe、pandas将多个Series对象当做数据列垂直合并形成dataframe
    Compose 动画艺术探索之属性动画
    大数据技术之Sqoop
    Ajax--Ajax加强--数据交换格式
    C++的单例模式
    Leetcode153. 寻找旋转排序数组中的最小值(无重复元素)
  • 原文地址:https://blog.csdn.net/unstoppableyi/article/details/137968532