【leetcode热题100】接雨水、直方图最大矩形面积、矩阵中最大的矩形

news2024/12/26 3:18:05

文章目录

  • 一、接雨水
    • 方法一:按列求(动态规划)
    • 方法二:双指针
    • 方法三:单调栈
  • 二、直方图最大矩形面积
    • 单调栈
    • 哨兵位优化
  • 三、矩阵中最大的矩形
    • 前缀和+单调栈

一、接雨水

题目链接

题目描述:

给定 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

方法一:按列求(动态规划)

我们把每一列能接的水加起来即可,而每一列的水只取决于当前列左边的最高墙和右边的最高墙
根据木桶效应,在左边和右边取低的那一个,然后减去当前列的高度即可求出当前列的接水量。
这样我们就可以创建两个数组,一个记录包括当前列左边的最高墙,一个记录包括当前列右边的最高墙,采用动态规划的思想。
为什么要包括当前列?

首先可以解决边界问题,其次如果当前列是左边最高的或者右边最高的,那么减去自己的高度就是0。

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        vector<int> leftMax(n), rightMax(n);
        int Max = 0;
        for(int i = 0; i < n; i++)
        {
            if(height[i] > Max)
            {
                Max = height[i];
            }
            leftMax[i] = Max;
        }
        Max = 0;
        for(int i = n - 1; i >= 0; i--)
        {
            if(height[i] > Max)
            {
                Max = height[i];
            }
            rightMax[i] = Max;
        }
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
            sum += min(leftMax[i], rightMax[i]) - height[i];
        }
        return sum;
    }
};

方法二:双指针

上面我们说过只用看左右两边最高墙中的最小值即可,所以现在我们定义两个指针,left从左向右,right从右向左,每次让小的那一列墙的指针向中间移动(因为我们不关心左边最高墙和右边最高墙中的高的那列墙)。

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        int leftMax = 0, rightMax = 0;
        int left = 0, right = n - 1;
        int sum = 0;
        while(left <= right)
        {
            if(height[left] < height[right])
            {
                leftMax = max(leftMax, height[left]);
                sum += leftMax - height[left];
                left++;
            }
            else
            {
                rightMax = max(rightMax, height[right]);
                sum += rightMax - height[right];
                right--;
            }
        }
        return sum;
    }
};

方法三:单调栈

用一个极端场景来举例子:
在这里插入图片描述
如果是单调递减的就依次入栈,直到碰到比栈顶元素要高的墙,此时就依次判断前面入栈且比当前墙要低的元素。

比方说现在到5下标。此时依次出栈之前的元素来计算接水量:
在这里插入图片描述

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();
        stack<int> st;
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
            while(!st.empty() && height[i] > height[st.top()])
            {
                int cur = st.top();
                st.pop();
                if(st.empty())
                {
                    break;
                }
                int len = i - st.top() - 1;
                sum += (min(height[st.top()], height[i]) - height[cur]) * len;
            }
            st.push(i);
        }
        return sum;
    }
};

二、直方图最大矩形面积

题目链接

题目描述:

给定非负整数数组 heights ,数组中的数字用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:
在这里插入图片描述

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

示例 2:
在这里插入图片描述

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

思路分析:

单调栈

这道题可以类比上面的接雨水问题,我们也可以用单调栈的方式来求解。
栈里面存的是下标,主要是用来计算宽度。
遍历每个下标,如果当前列大于栈顶元素,就继续入栈,如果小于栈顶元素,进行处理:
在这里插入图片描述
从1开始遍历,当遍历到1的位置时还不能确定1位置是不是最大的矩形面积,继续向后遍历,当遍历到2的位置时,就可以确定2之前的的大面积了。
在这里插入图片描述
如果已经确定了一个柱形的高度,我们可以无视它(出栈)。
在这里插入图片描述
为什么可以无视呢?
后边的元素一定比1要小,所以当要求最大面积的时候一定会跨过第一列:
在这里插入图片描述
就算1前面也有元素也是可以可以直接跨过。
可以看到2不用关注1,3不用关注1和2。

这里还有两个特殊的情况:
1️⃣ 弹栈的时候,栈为空;
2️⃣ 遍历完成以后,栈中还有元素;

如果弹栈的时候栈为空,那么说明宽度要从当前位置一直延伸到0下标。
如果遍历完后栈中还有元素。比如说这个图:
在这里插入图片描述
最后剩下的就是4和6,对于4和6,先处理6在处理4:
在这里插入图片描述

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        stack<int> st;
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            while(!st.empty() && heights[i] < heights[st.top()])
            {
                int mid = st.top();
                st.pop();
                int w = i;
                if(!st.empty())
                {
                    w = i - st.top() - 1;
                }
                ans = max(ans, w * heights[mid]);
            }
            st.push(i);
        }
        while(!st.empty())
        {
            int mid = st.top();
            st.pop();
            int w = n;
            if(!st.empty())
            {
                w = n - st.top() - 1;
            }
            ans = max(ans, w * heights[mid]);
            cout << w * heights[mid] << endl;
        }
        return ans;
    }
};

哨兵位优化

为了处理上面两个特殊情况,我们可以在首位都添加一个0。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.insert(heights.begin(), 0);
        heights.push_back(0);
        int n = heights.size();
        stack<int> st;
        st.push(0);
        int ans = 0;
        for(int i = 1; i < n; i++)
        {
            while(heights[i] < heights[st.top()])
            {
                int mid = st.top();
                st.pop();
                int left = st.top();
                int right = i;
                int w = right - left - 1;
                ans = max(ans, w * heights[mid]);
            }
            st.push(i);
        }
        return ans;
    }
};

三、矩阵中最大的矩形

题目链接

题目描述:

给定一个由 0 和 1 组成的矩阵 matrix ,找出只包含 1 的最大矩形,并返回其面积。
注意:此题 matrix 输入格式为一维 01 字符串数组。

示例 1:
在这里插入图片描述

输入:matrix = [“10100”,“10111”,“11111”,“10010”]
输出:6
解释:最大矩形如上图所示。

示例 2:

输入:matrix = []
输出:0

示例 3:

输入:matrix = [“0”]
输出:0

示例 4:

输入:matrix = [“1”]
输出:1

示例 5:

输入:matrix = [“00”]
输出:0

思路分析:
例如上面的图,我们可以分层看,每一层都是求直方图最大矩形面积。

第一层柱状图的高度[“1”,“0”,“1”,“0”,“0”],最大面积为1;
第二层柱状图的高度[“2”,“0”,“2”,“1”,“1”],最大面积为3;
第三层柱状图的高度[“3”,“1”,“3”,“2”,“2”],最大面积为6;
第四层柱状图的高度[“4”,“0”,“0”,“3”,“0”],最大面积为4;

这道题的解法就是前缀和+单调栈

前缀和+单调栈

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        stack<int> st;
        st.push(0);
        int ans = 0;
        for(int i = 1; i < n; i++)
        {
            while(heights[i] < heights[st.top()])
            {
                int mid = st.top();
                st.pop();
                int left = st.top();
                int right = i;
                int w = right - left - 1;
                ans = max(ans, w * heights[mid]);
            }
            st.push(i);
        }
        return ans;
    }

    int maximalRectangle(vector<string>& matrix) {
        if(matrix.size() == 0) return 0;
        int res = 0;
        vector<int> v(matrix[0].size() + 2);
        for(int i = 0; i < matrix.size(); i++)
        {
            for(int j = 0; j < matrix[i].size(); j++)
            {
                if(matrix[i][j] == '1')
                {
                    v[j + 1] += 1;
                }
                else
                {
                    v[j + 1] = 0;
                }
            }
            res = max(res, largestRectangleArea(v));
        }
        return res;
    }
};


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496198.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM_垃圾回收器

目录 一、GC分类1.串行vs并行2.并发式vs独占式3.压缩式vs非压缩式4.年轻代vs老年代 二、GC评估指标1.吞吐量2.暂停时间3.小结 三、垃圾回收器都有哪些&#xff1f;1.GC发展史2.7种GC组合关系&#xff1f;3.为什么这么多GC4.如何查看默认GC?5.Serial GC&#xff1a;串行回收5.1…

字符设备驱动开发实验

我们以 chadev 这个虚拟设备为 例&#xff0c;完整的编写一个字符设备驱动模块。chadev 不是实际存在的一个设备&#xff0c;是为了方 便讲解字符设备的开发而引入的一个虚拟设备设备有两个缓冲区&#xff0c;一个为读缓冲 区&#xff0c;一个为写缓冲区&#xff0c;这两个缓冲…

Spring事务隔离级别详解

Spring有五大隔离级别&#xff1a; 1、ISOLATION_DEFAULT 2、ISOLATION_READ_UNCOMMITTED 3、ISOLATION_READ_COMMITTED 4、ISOLATION_REPEATABLE_READ 5、ISOLATION_SERIALIZABLE ISOLATION_DEFAULT 用底层数据库的设置隔离级别。 ISOLATION_READ_UNCOMMITTED 一个事…

java 数组创建的方法

数组是一个由一组元素组成的集合&#xff0c;我们可以用一个数组来表示集合。 java中最基本的数据类型是字符串&#xff0c;其长度是固定的&#xff0c;且不可变&#xff0c;一个字符串只能以一个数字开头。 在 Java中我们可以通过 myConst关键字来指定数组的长度。下面就看一下…

直线飙升到10万+star的AutoGpt,有多强?帮我写了个网页!

先来感受一下10万的star&#xff0c;到底有多强&#xff01; 从4月2日开始&#xff0c;直线飙升到10万star Auto-GPT是一个实验性的开源应用程序&#xff0c;展示了GPT-4语言模型的功能。这个程序由GPT-4驱动&#xff0c;将LLM“思想”链接在一起&#xff0c;以自主实现您设定的…

CTO解读:从“RSAC 2023”到“韧性数据安全”—Stronger Together

一年一度RSA Conference已落下帷幕。作为全球最具规模的安全大会&#xff0c;每年一届的RSAC都是安全行业的风向标。 2023年RSAC的主题是&#xff1a;Stronger Together&#xff0c;一起更强大。安全产品往往是场景化的&#xff0c;单点产品解决不同的问题&#xff0c;有机的整…

QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样

QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样 [1] QT自制软键盘 最完美、最简单、跟自带虚拟键盘一样一、本自制虚拟键盘特点二、windows打开系统自带软键盘三、让键盘界面保持在最上方、不改变底层界面焦点四、长按按键重复输入键盘内容五、模拟键盘点击事件完成虚拟键盘…

虹科方案|使用 HK-TRUENAS支持媒体和娱乐工作流程-2

一、支持 M&E 工作流程的HK-TRUENAS 屡获殊荣的 TrueNAS 存储解决方案支持单独的工作空间来存放可在现场或制作室访问的媒体资产。 TrueNAS 提供企业功能&#xff0c;支持多个物理和虚拟应用程序&#xff0c;并具有同步块和文件存储访问。 这些功能允许备份和重新利用视频、…

路由递归配置

路由递归原理 路由必须有直连的下一跳才能够指导转发,但是路由生成时下一跳可能不是直连的,因此需要计算出一个直连的下一跳和对应的出接口,这个过程就叫做路由递归 。 路由递归也被称为路由 迭代。 实验配置 路由器R1配置 interface GigabitEthernet0/0/0ip address 192.…

《编程思维与实践》1049.GPS数据处理

《编程思维与实践》1049.GPS数据处理 题目 思路 注记: UTC为世界标准时间(0时区),东区加,西区减. 分两步实现: 1.判断是否为有效的语句: 有效需要满足三个条件: ①语句含$GPRMC,可以通过strstr搜索来判断; ②状态已定位,可以用sscanf来读取判断; ③异或结果与校验值相同,校验值…

【Vue学习笔记6】好用的 Vueuse 工具包

1. 安装Vueuse VueUse 的官方&#xff08;https://vueuse.org/&#xff09;的介绍说这是一个 Composition API 的工具集合&#xff0c;适用于 Vue 2.x 或者 Vue 3.x&#xff0c;用起来和 React Hooks 还挺像的。 VueUse 插件的安装 npm install vueuse/core2. 实现全屏功能 …

【三十天精通Vue 3】第二十七天 Vue 3的实战案例-接口进度条

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: 三十天精通 Vue 3 文章目录 引言一、安装进度条插件1.1 安装NProgress插件1.2 在Vue3中引入NProgress插件二、在路由中使用进度条2.1 在全局路由中使用进度…

ubuntu20.04安装搜狗输入法

搜狗输入法下载网址&#xff1a; https://shurufa.sogou.com/linux 选择x86_64版本 打开 系统设置——区域和语言——管理已安装的语言——在“语言”tab下——点击“添加或删除语言” 弹出“已安装语言”窗口&#xff0c;勾选中文&#xff08;简体&#xff09;&#xff0c;点…

【RPC、WebSocket】

文章目录 有HTTP协议为什么还要RPCTCPHTTP 和 RPCHTTP 和 RPC 有什么区别 有HTTP协议为什么还要WebSocket使用HTTP不断轮询长轮询WebSocket怎么建立WebSocket连接 有HTTP协议为什么还要RPC TCP TCP三个特点&#xff1a;面向连接、可靠、基于字节流。 基于字节流 字节流可以理…

Disabled PicPipeline: ImagesPipeline requires installing Pillow 4.0.0 or later

目录 一、scrapy是什么 二、问题以及原因 三、解决办法 1、确保系统已经安装了 Pillow 库。 2、安装 Pillow 库。 3、在项目根目录中添加 Pillow 的 .pth 文件。 一、scrapy是什么 Scrapy是一个用于从网站和Web应用中抓取数据的强大的Python库。Scrapy支持异步I/O和 Scr…

销售数据分析怎么做?这篇文章说清楚了

如何分析销售数据&#xff1f;分析销售数据有哪些指标&#xff1f;销售数据分析有什么作用&#xff1f; 销售数据是不是得通过数据分析软件啊&#xff1f; 本文将为您解答疑惑—— 一、分析销售数据的指标 从两个层面上来讲&#xff0c;一个是对销售情况的整体把控&#xf…

大学校友会管理APP系统开发 重温同学梦再叙校园情

互联网技术的深入发展&#xff0c;让各行各业对网络的依赖都逐渐加深&#xff0c;可以说网络在今天已经成为无数个你我他不可或缺的平台。学生时代是一生中最美好的时期&#xff0c;校友是社会高效重要的社会资本和无形资产&#xff0c;校友与校友之间信息交流也需要依靠互联网…

虚拟化转向容器的新方案,红帽正式推出虚拟化容器统一平台——openshift虚拟化

编辑 | 宋慧 出品 | CSDN 云计算 云原生、容器化&#xff0c;是近年 IT 界主要的话题之一。 数字化转型的浪潮下&#xff0c;技术在朝向更加有利于业务快速迭代的方向发展。据 CSDN 最新年度《中国开发者调查报告》数据显示&#xff0c;近一半的公司&#xff08;43%&#xff0…

爬虫|Python|ts格式的加密视频合并方法

前言&#xff1a; 爬虫的一些基本概念&#xff1a; 对于爬虫来说&#xff0c;没有道德&#xff08;比如&#xff0c;某些爬虫上w的并发&#xff0c;那么&#xff0c;一些小站可能就会崩溃&#xff0c;其实爬虫也是可以作为网络攻击的&#xff0c;假设有需要攻击的网站&#x…

Shell 脚本传递参数的两种方式:位置传参与指令式传参

Shell 脚本传递参数的两种方式 方式一&#xff1a;数字传参 直接传参 数字传递可以用$1 $2 $3 ......获取第一个第二个第三个参数&#xff0c;$0获取命令&#xff08;也就是你的文件名&#xff09;&#xff0c;$#可以查看总的参数个数 以下文件命名为param1&#xff08;shel…