单调栈(C++)

单调栈,即栈中元素是单调递增的或是单调递减的,是一个比较好用的数据结构.

柱状图中最大的矩形

84. 柱状图中最大的矩形 - 力扣(LeetCode)

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

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

在这里插入图片描述

​ 注意到,当从左向右看,并尝试计算面积时,总是在前一个比后一个大的时候才会尝试计算, 如果柱子高度是单增的,那么显然会有更大的面积,只有变矮时,才不会右更大的面积.

​ 那么,我们可以创建一个单增的栈,里面存储各个柱的序号,如果后续时单增的,就一直入栈,如果当前元素比栈顶元素小,就出栈,并计算面积.这样只需要一次遍历就可以计算得出.

在这里插入图片描述

(画红虚线的为最终栈中元素)

​ 注意边界问题,在遍历一次柱状图后,栈中可能还会有剩余元素.显然它们是单增的,那么从右往左看,直到栈中的前一个元素,都是可计算面积的.即

	length = res.top();res.pop();//pop后的栈顶元素即为约束width = res.empty()?n:n-res.top()-1;//已经出栈,则宽度多算了1,为空的话,则说明这个元素是最小的.

完整代码:

class Solution {
public:int largestRectangleArea(vector<int>& heights) {unsigned long n = heights.size();if (n == 1){return heights[0];}stack<int> res;int ans=0;//使用一个单增的栈,一遇到单减,立马出栈,计算面积for(int i=0;i<n;i++){while(!res.empty()&&heights[res.top()]>heights[i]){int length=heights[res.top()];res.pop();//使用后立即出栈,良好习惯int width = res.empty()?i:i-res.top()-1;//注意已经出栈,宽度比实际面积大1,手动减去ans = max(ans,length*width);}res.push(i);}//完成后可能栈非空,再来一次while(!res.empty()){int length=heights[res.top()];res.pop();int width =res.empty()?n : n -res.top()-1;ans = max(ans,length*width);}return ans;}
};

接雨水

42. 接雨水 - 力扣(LeetCode)

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

在这里插入图片描述

​ 注意到当柱子单减时,突然变大了,则可以接雨水,可以使用单减栈(注意接雨水需要墙,而边界不算墙),判断是否能接水,至少需要三根柱子: c u r , l e f t , r i g h t cur,left,right cur,left,right.

c u r cur cur表示判断可能可以接水的地方,即他的下一个柱子即 r i g h t right right,是比它高的,那么认为, l e f t ∼ r i g h t left\sim right leftright这片区域(不含边界,是开的)的高度均为cur,为什么可以这样认为后续会进一步讲解.那么这三根柱子带来的雨水收益为: ( m i n ( l e f t , r i g h t ) − h e i g h t [ c u r ] ) ∗ ( r i g h t − l e f t − 1 ) ) (min(left,right)-height[cur])*(right-left-1)) (min(left,right)height[cur])(rightleft1))

​ 现在解释为什么可以认为 l e f t ∼ r i g h t left\sim right leftright这片区域可认为高度均为cur:

  • 显然这片区域没有比 c u r cur cur更高的柱子
  • 如果高度均为 h e i g h t [ c u r ] height[cur] height[cur],那么显然成立
  • 如果有比 c u r cur cur低的柱子 p p p,那么在区间 [ c u r , r i g h t ] [cur,right] [cur,right],可认为高度均为 p p p,已经被计算过雨水面积为 ( m i n ( c u r , r i g h t ) − p ) ∗ ( r i g h t − c u r − 1 ) (min(cur,right)-p)*(right-cur-1) (min(cur,right)p)(rightcur1),也就是说那些实际比cur低的但在此次计算中被认为是柱子的空白部分,是被计算过了的.

​ 这是一个递归的过程,如果不太能理解,可以看例子中的序号3到6这一区间的计算过程,你会发现在计算序号5的柱子接水时,加且仅加了1,在后续的计算中,这一方格被自动地认为是柱子,不再认为是空白.

class Solution {
public:int trap(vector<int>& height) {//注意到,只要单减时遇到变大,就可以接水,考虑单调栈stack<int> st;int res=0;int len=height.size();for(int i=0;i<len;i++){while(!st.empty()&&height[st.top()]<height[i]){int cur=st.top();st.pop();if(st.empty())break;//由于接水需要左右两边都有墙,如果弹出后为空,说明左边没墙,结束,否则溢出int l=st.top();int r=i;int h=min(height[l],height[r])-height[cur];res+=(r-l-1)*h;}st.push(i);}return res;}
};

最大矩形

85. 最大矩形 - 力扣(LeetCode)

给定一个仅包含 0 和 1 、大小为 $rows \times cols $ 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

在这里插入图片描述

​ 注意到这是一个二维的单减栈(最小栈)问题,即每一行都用单调栈处理一次即可.

​ 相当于是每一行都是一个柱状图,而柱状图高度取决于有多少个连续的1,使用height[cols]来维护.

class Solution {
public:int maximalRectangle(vector<vector<char>>& matrix) {if(matrix.empty())return 0;int rows=matrix.size();int cols=matrix[0].size();int maxarea=0;vector<int> height(cols,0);//对每一行都进行计数,并通过最小栈计算出每一行最大的矩形for(int i=0;i<rows;i++){for(int j=0;j<cols;j++){if(matrix[i][j]=='1')height[j]++;else height[j]=0;}//注意一列中必须有连续的1才能++,否则就更新为0stack<int> st;for(int j=0;j<cols;j++){while(!st.empty()&&height[st.top()]>height[j]){int length = height[st.top()];st.pop();int weight = st.empty()?j:j-st.top()-1;maxarea=max(maxarea,length*weight);}st.push(j);            }while(!st.empty()){int length = height[st.top()];st.pop();int weight = st.empty()?cols:cols-st.top()-1;maxarea=max(maxarea,length*weight);}}return maxarea;}
};

单调栈模板

	//单减栈(最小栈)for(int i =0;i<len;i++){while(!st.empty()&&heights[st.top()]>heights[i]){//单增栈(最大栈)只需要改成小于就好int height = heights[st.top()];st.pop();int width = st.empty()?i:i-st.top()-1;area = height*width}st.push(i);}//如果需要处理栈中剩余元素,则还需要while(!st.empty()){int height = heights[st.top()];st.pop;int width = st.empty()?len:len-st.top()-1;area = height*width;}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IRIS / Chronicles 数据库结构

对于我们用得最多的关系型数据库来说&#xff0c;首先有的是数据库名字&#xff0c;然后是表名字&#xff0c;然后就是字段名&#xff0c;随后就是一条一条的数据。 对于 IRIS 来说&#xff0c;因为是使用的层级数据库&#xff0c;所以上面的定义就不能完全的照搬了&#xff0…

Java 学习和实践笔记(49):用javabean和一维数组的方式来存储表格数据

还是存储下面这个表格的数据&#xff0c;但使用另一种方法来做。 用javabean和一维数组的方法来做&#xff0c;示例代码如下&#xff1a; /*先创建一个类&#xff0c;其实就是创建好一个只有各属性列的空表格*/ class Employees {private int id;private String name;private …

vue2高德地图选点

<template><el-dialog :title"!dataForm.id ? 新建 : isDetail ? 详情 : 编辑" :close-on-click-modal"false" :visible.sync"show" class"rv-dialog rv-dialog_center" lock-scroll width"74%" :before-close&q…

未能加载文件或程序集socutdata或它的某一个依赖项试图加载格式不正确的程序

未能加载文件或程序集socut data或它的某一个依赖项试图加载格式不正确的程序 Socut.Data.dll找不到类型或命名空间名称 把bin目录下面 的socut.data.dll删除就行了 C#报错未能加载文件或程序集socut data或它的某一个依赖项试图加载格式不正确的程序 "/"应用程序…

MySQL数据库----------探索高级SQL查询语句 (二)

目录 一、子查询 1.1多表查询 1.2多层嵌套 1.3 insert语句子查询 1.4update语句子查询 1.5delete语句子查询 1.6EXISTS 1.7子查询&#xff0c;别名as 二、mysql视图 2.1mysql视图介绍 2.2mysql作用场景[图]: 2.3视图功能&#xff1a; 2.4视图和表的区别和联系 区别…

Flink on Kubernetes (flink-operator) 部署Flink

flink on k8s 官网 https://nightlies.apache.org/flink/flink-kubernetes-operator-docs-release-1.1/docs/try-flink-kubernetes-operator/quick-start/ 我的部署脚本和官网不一样&#xff0c;有些地方官网不够详细 部署k8s集群 注意&#xff0c;按照默认配置至少有两台wo…

淘宝详情数据采集(商品上货,数据分析,属性详情,价格监控),海量数据值得get

淘宝详情数据采集涉及多个环节&#xff0c;包括商品上货、数据分析、属性详情以及价格监控等。在采集这些数据时&#xff0c;尤其是面对海量数据时&#xff0c;需要采取有效的方法和技术来确保数据的准确性和完整性。以下是一些关于淘宝详情数据采集的建议&#xff1a; 请求示…

快速上手Spring Cloud四:微服务治理与安全

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

P8649 [蓝桥杯 2017 省 B] k 倍区间:做题笔记

目录 思路 代码思路 代码 推荐 P8649 [蓝桥杯 2017 省 B] k 倍区间 思路 额嗯&#xff0c;这道题我刚上来是想到了前缀和&#xff0c;但是还要判断每个子序列&#xff0c;我就两层for嵌套&#xff0c;暴力解了题。就是我知道暴力肯定过不了但是写不出来其他的[留下了苦…

『Apisix』破局传统架构:探索新一代微服务体系下的API管理新范式与最佳实践

文章目录 『Apisix基石篇』『Apisix入门篇』『Apisix进阶篇』『Apisix安全篇』 『Apisix基石篇』 &#x1f680; 手把手教你从零部署APISIX高性能API网关 利用Docker-compose快速部署Apache APISIX及其依赖组件&#xff0c;实现高效的API网关搭建通过编写RPM安装脚本来自动化安…

国际伦敦金行情分析中的趋势分析方法

国际伦敦金行情走势复杂多变。近期&#xff0c;金价曾经一度刷新历史的新高点至2222&#xff0c;但就在当天&#xff0c;金价又快速下跌跌超过30美元。不过这么多变的伦敦金行情也为我们的交易创造了空间&#xff0c;有空间就等于有机会&#xff0c;只要我们能够掌握国际伦敦金…

Diffusion添加噪声noise的方式有哪些?怎么向图像中添加噪声?

添加噪声的方式大致分为两种&#xff0c;一种是每张图像在任意timestep都加入一样的均匀噪声&#xff0c;另一种是按照timestep添加不同程度的噪声 一、在任意timestep都加入一样的noise batch_size 32x_start torch.rand(batch_size,3,256,256) noise torch.randn_like(x_…