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

news/2024/11/9 3:06:58/

文章目录

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

一、接雨水

题目链接

题目描述:

给定 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.ppmy.cn/news/60767.html

相关文章

最强无监督单目深度估计Baseline--MonoViT--简介与代码复现

1. 无监督单目深度估计 单目深度估计是指&#xff0c;借助于深度神经网络&#xff0c;从单张输入视图中推理场景的稠密深度信息&#xff1b;该技术可以广泛用于自动驾驶、虚拟现实、增强现实等依赖于三维场景感知理解的领域&#xff0c;同时也可以为其他视觉任务提供多模态深度…

hd debug - DAPLink的资料

文章目录 DAPLink的资料概述笔记库迁出的技巧END DAPLink的资料 概述 查资料时, 看到有DAPLink的资料, 记录一下. 笔记 DAPLink项目分为软件和硬件2部分, 不在一个库中. 总览 : https://daplink.io/ 这个页面上说了软件和硬件项目的库地址. 软件库地址 : https://github.…

SVM(基于李航统计学习方法,包含SMO)

文章目录 线性可分SVM和硬间隔最大化函数间隔和几何间隔间隔最大化支持向量 学习的对偶算法 线性SVM和软间隔最大化支持向量 非线性SVM和核函数SMO算法求解二次规划选择变量第一个变量第二个变量 计算 b b b 和 E i E_i Ei​ 线性可分SVM和硬间隔最大化 函数间隔和几何间隔 …

Ceres简介及示例(7)On Derivatives(Spivak Notation)

On Derivatives Ceres求解器&#xff0c;像所有基于梯度的优化算法一样&#xff0c;依赖于能够评估目标函数及其在其域内任意点的导数。实际上&#xff0c;定义目标函数及其雅可比矩阵是用户在使用Ceres求解器求解优化问题时需要执行的主要任务。正确、高效的雅可比矩阵计算是…

man,cp,mv,alias,more,less,head,tail指令与文件片段读取和管道的初步介绍

tips 文件夹就是目录定位某个文件的位置&#xff0c;本质上就是在Linux的多叉树目录结构下去定位它的位置文件名主干&#xff08;不考虑前缀路径&#xff09;以. 开头的文件就被称为隐藏文件任何一个目录下面都有一个.隐藏文件与…隐藏文件无论window还是Linux&#xff0c;常识…

ChatGPT带你一起了解C语言中的fopen()

fopen()是一个C语言标准库函数&#xff0c;用于打开文件并返回其指针&#xff0c;以进行后续的读写操作。该函数原型如下&#xff1a; FILE *fopen(const char *filename, const char *mode); 其中&#xff0c;filename参数表示要打开的文件名&#xff0c;可以包含完整路径或…

【华为OD机试 2023最新 】任务总执行时长(C语言题解 100%)

文章目录 题目描述输入描述输出描述用例题目解析代码思路C语言题目描述 任务编排服务负责对任务进行组合调度。 参与编排的任务有两种类型,其中一种执行时长为taskA,另一种执行时长为taskB。 任务一旦开始执行不能被打断,且任务可连续执行。 服务每次可以编排num个任务。…

Java中的注解和反射

注解 在Java程序中&#xff0c;我们可以在很多地方看到注解&#xff0c;如一下情况: 注解有检查和约束的作用 内置注解 当被Deprecated注解修饰的方法被使用的时候&#xff0c;方法会被画上杠&#xff1a; 元注解 当我们打开一个注解的时候&#xff0c;可以看到以下这些信…