当前位置: 首页 > article >正文

代码随想录:动态规划4-5

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

代码

class Solution {
    public int trap(int[] height) {

        //雨水的关键是找凹槽,凹槽是栈顶的mid,右边柱子是当前更大的元素,左边的柱子是栈顶下面的元素
        //单调递减栈:寻找右边第一个更大的元素
        Stack<Integer> stack = new Stack<>();
        //栈中放的是元素下标,第一个元素入栈,高度=height[0]
        stack.push(0);

        int sum = 0;  //初始雨水

        //i是当前元素下标,height[i]是当前元素高度
        for(int i=1; i < height.length; i++){
            //当前元素高度 < 栈顶元素高度
            if(height[i] < height[stack.peek()]){
                stack.push(i);  //当前元素下标入栈
            }
            //当前元素高度 = 栈顶元素高度
            else if(height[i] == height[stack.peek()]){
                //因为栈顶高度和当前元素高度,栈顶的柱子肯定没有雨水
                stack.pop();  //栈顶元素入栈
                stack.push(i);  //当前元素下标入栈
            }
            //当前元素高度 > 栈顶元素高度,出现凹槽
            else{
                //只要当前元素高度比栈顶元素高度大,循环处理所有凹槽
                while(!stack.isEmpty() && height[i] > height[stack.peek()]){
                    int mid = stack.pop();  //凹槽下标

                    //mid出栈后,如果栈为空,说明mid左边是空的,没有雨水,[1],mid=1,1出栈就行
                    //mid出栈后,如果栈非空,说明mid左边不空,有雨水,需要计算雨水量
                    if(!stack.isEmpty()){
                        int left = stack.peek();  //凹槽左边下标
                        //mid凹槽的雨水高度 = 左右高度最小值-凹槽高度
                        int h = Math.min(height[i], height[left]) - height[mid];
                        //mid凹槽的雨水宽度
                        int w = i - left - 1;  //这里要写- left - 1,不能写-mid,[4,2,0,3,2,5]画个图就知道了
                        int area = h * w;  //mid凹槽雨水量
                        sum += area;   
                    }
                }
                stack.push(i);//当前元素下标入栈
            }
        }
        return sum;  //返回总雨水量
    }
}

84.柱状图中最大的矩形

题目

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

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

示例 1:

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

示例 2:

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

代码

class Solution {
    public int largestRectangleArea(int[] heights) {
        //关键是找变小的元素,变小了,就把前面的矩形面积计算出来

        //扩容,头尾加元素0
        int[] newHeights = new int[heights.length + 2];
        //头部加0,防止出现[8,6,4,2]递减序列算出来是0
        newHeights[0] = 0;
        //尾部加0,防止出现[2,4,6,8]递增序列算出来是0
        newHeights[newHeights.length - 1] = 0;
        //数组copy
        for(int i=0; i < heights.length; i++){
            newHeights[i+1] = heights[i];
        }

        int res = 0; //初始最大面积
        //单调栈,找右边第一个更小的元素
        Stack<Integer> stack = new Stack<>();
        //第一个元素下标入栈
        stack.push(0);  

        for(int i=1; i < newHeights.length; i++){
            //当前元素高度 > 栈顶元素高度
            //举例:[1,5,6]持续入栈
            if(newHeights[i] > newHeights[stack.peek()]){
                stack.push(i);  //下标入栈
            }
            //当前元素高度 = 栈顶元素高度
            //举例:[1,5,5,6],当前元素=2,最大值会在第一个5取到,5不用出栈
            else if(newHeights[i] == newHeights[stack.peek()]){
                stack.push(i);  //下标入栈
            }
            //当前元素高度 < 栈顶元素高度
            else{
                //[1,5,6],当前元素=2,要出栈循环计算矩形大小
                while(!stack.isEmpty() && newHeights[i] < newHeights[stack.peek()]){
                    int mid = stack.pop();  //6的下标
                    if(!stack.isEmpty()){
                        int left = stack.peek();  //5的下标
                        int h = newHeights[mid]; //高度是6
                        int w = i - left - 1;  //宽度是1
                        int area = h * w; //面积是6
                        res = Math.max(res, area);  //更新最大矩形面积
                    }
                }
                stack.push(i);
            }
        }
        return res;
    }
}

http://www.kler.cn/news/308575.html

相关文章:

  • Java技术深度探索:高并发场景下的线程安全与性能优化
  • java面试题-Sql 语句的执行顺序
  • 【SOP】使用MMDeploy将MMAction2的模型转换为TensorRT
  • 二叉树的前中后序遍历(递归法)( 含leetcode上三道【前中后序】遍历题目)
  • java-lambda-常用方法总结汇总
  • 【乐企】旅客运输发票接口实现
  • 第159天:安全开发-Python-协议库爆破FTPSSHRedisSMTPMYSQL等
  • 持续集成与持续交付CI/CD
  • TDengine 首席架构师肖波演讲整理:探索新型电力系统的五大关键场景与挑战
  • CentOS7下安装Ruby3.2.4的实施路径
  • LeetCode_sql_day26(184,1549,1532,1831)
  • ubuntu系统服务器离线安装python包
  • 力扣(leetcode)每日一题 2848 与车相交的点
  • 7天速成前端 ------学习日志 (继苍穹外卖之后)
  • Spire.PDF for .NET【页面设置】演示:为 PDF 添加背景颜色或背景图像
  • python压缩图片的代码
  • 《锐捷AP 胖模式配置示例》
  • UiBot教程:实现复杂流程图的高效方法
  • C++学习笔记(21)
  • solidity-21-call_contract
  • 华为SMU02B1智能通信电源监控单元模块简介
  • 基于SpringBoot+Vue的养老院管理系统
  • 在Ubuntu中编译含有JSON的文件出现报错
  • 【前后端】大文件切片上传
  • 网络安全学习(一)初识kali
  • 【JavaEE初阶】多线程(5 单例模式 \ 阻塞队列)
  • 构建基于 Feign 的微服务:从 Eureka 到负载均衡的实践 --day05
  • 微信支付开发-前端api实现
  • 大模型笔记03--快速体验dify
  • HTTP的强制缓存和协商缓存有什么区别和联系?