Day55_20250203_单调栈part2_42.接雨水|84.柱状图中最大的矩形

Day55_20250203_单调栈part2_42.接雨水|84.柱状图中最大的矩形

42.接雨水

题目

【单调栈应用高频题目,在面试中建议掌握双指针和单调栈】

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 10<sup>4</sup>
  • 0 <= height[i] <= 10<sup>5</sup>

思路

  • 思路
    • 单调递减栈,栈里存的是柱子的索引,保证栈内元素的高度是单调递减的。
    • 遍历height数组
      • 当前元素<=栈顶元素, 递减的,直接入栈
      • 当前元素>栈顶元素,形成洼地,计算积水
        • pop栈顶,作为bottom
        • 判断栈是否为空
          • 如果为空,break
          • 如果不为空,计算左右两边围成的水池
            • 宽度,int width = i - left - 1;
            • 高度,int heightWater = Math.min(height[left], height[i]) - height[bottom];
        • 更新总积水量:water += width * heightWater; // 更新总积水量
      • 继续遍历,入栈i,确保栈中存储的柱子始终递减
  • 代码
    class Solution {
        public int trap(int[] height) {
            if (height == null || height.length < 3) return 0; // 边界情况
    
            Stack<Integer> stack = new Stack<>(); // 单调递减栈,存储柱子的索引
            int water = 0;
    
            for (int i = 0; i < height.length; i++) {
                //栈不为空,且当前遍历元素>栈顶元素,有可能形成洼地,需要计算积水。
                while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                    int bottom = stack.pop(); // pop栈顶,作为低洼处的索引
                    if (stack.isEmpty()) break; // 栈空了,说明左侧没有柱子了,无法存水
                    //如果栈不为空,计算左右两边围成的水池
                    int left = stack.peek(); // 左侧柱子的索引,仅仅获取,不弹出
                    // 宽度:i为低洼处右边的高处的元素-左-1
                    int width = i - left - 1; 
                    // 高度:两边的最低处-低洼处
                    int heightWater = Math.min(height[left], height[i]) - height[bottom];
                    water += width * heightWater; // 更新总积水量
                }
                //当前遍历元素<=栈顶元素,单调递减,直接入栈
                stack.push(i); // 当前柱子入栈
            }
            return water;
    
        }
    }
    

总结

  • 难题,难点在于怎么计算高度和宽度的代码思路。

84.柱状图中最大的矩形

题目

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

提示:

  • 1 <= heights.length <=10<sup>5</sup>
  • 0 <= heights[i] <= 10<sup>4</sup>

思路

  • 思路
    • 单调递减栈
    • 遍历newHeight数组,
      • 当前元素>=栈顶元素,直接入栈
      • 当前元素<栈顶元素,以栈顶为基准,计算按照栈顶高度形成的面积。
    • 继续入栈stack.push(i);
  • 代码
    class Solution {
        public int largestRectangleArea(int[] heights) {
            int[] newHeight=new int[heights.length+2];
            //将heights数组复制到newHeight数组中
            System.arraycopy(heights,0,newHeight,1,heights.length);
            //扩展数组 首尾各扩展1个0
            newHeight[heights.length+1]=0;
            newHeight[0]=0;
    
            //单调递减栈
            Stack<Integer> stack=new Stack<>();
            stack.push(0);//放入第一个元素
    
            int res=0;//存储结果
            for(int i=1;i<newHeight.length;i++){
                //当前元素<栈顶元素
                while(newHeight[i]<newHeight[stack.peek()]){
                    int mid=stack.pop();//pop栈顶,作为基准
                    int left=stack.peek();
                    int w=i-left-1;//宽度:右-左-1
                    int h=newHeight[mid];//高度:以mid为基准
                    res=Math.max(res,w*h);//更新最终结果
                }
                stack.push(i);//继续入栈
            }
            return res;
        }
    }
    

总结

  • 为什么要在首尾各扩展1个0【扩展数组】?
    • 保证栈中的每个元素最终都能计算出面积。例如递增数组[8,6,4,2],在8入栈后,6与8比较,得到mid(8),right(6),但得不到left。
    • 避免特殊情况。当栈非空时没有更多的柱子可以比较,加入0统一处理这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值