单调栈(C++)

news2024/9/30 5:29:19

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

柱状图中最大的矩形

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才能++,否则就更新为0
            stack<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.coloradmin.cn/o/1550314.html

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

相关文章

【SAP2000】在框架结构中应用分布式面板荷载Applying Distributed Panel Loads to Frame Structures

在框架结构中应用分布式面板荷载 Applying Distributed Panel Loads to Frame Structures 使用"Uniform to Frame"选项,可以简单地将荷载用于更多样化的情况。 With the “Uniform to Frame” option, loads can be easily used for a greater diversity of situat…

【书生·浦语大模型实战营第二期】学习笔记1

1. Introduction 开源llm举例&#xff1a;LLaMA 、Qwen 、Mistral 和Deepseek 大型语言模型的发展包括预训练、监督微调&#xff08;SFT&#xff09;和基于人类反馈的强化学习&#xff08;RLHF&#xff09;等主要阶段 InternLM2的显著特点 采用分组查询注意力&#xff08;GQA…

蓝桥杯基础练习汇总详细解析(三)——字母图形、01字符串、闰年判断(详细解题思路、代码实现、Python)

试题 基础练习 字母图形 提交此题 评测记录 资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 利用字母可以组成一些美丽的图形&#xff0c;下面给出了一个例子&#…

web开发发展历程-前端、后端、消息队列、后端架构演进

文章目录 摘要主要内容不同的时代对应不同的技术前端技术的中间阶段-单页面应用前后端分离后端技术演化-云计算平台总体趋势反应式编程 消息队列发展史kafka&#xff0c;rocketmq&#xff0c;pulsar网易后端架构演进架构瓶颈数据库瓶颈服务器瓶颈数据库缓存瓶颈-缓存击穿、雪崩…

Spring Boot:Web开发之三大组件的整合

Spring Boot 前言Spring Boot 整合 ServletSpring Boot 整合 FilterSpring Boot 整合 Listener 前言 在 Web 开发中&#xff0c;Servlet 、Filter 和 Listener 是 Java Web 应用中的三大组件。Servlet 是 Java 代码&#xff0c;通过 Java 的 API 动态的向客户端输出内容。Filt…

7.3*3卷积核生成

1.卷积核 在数字图像处理中的各种边沿检测、滤波、腐蚀膨胀等操作都离不开卷积核的生成。下面介绍如何生成各种3X3的卷积核。为后面的数字图像操作打下基础。   由于图像经过卷积操作后会减少两行两列&#xff0c;因此在生成卷积核的时候一般会对图像进行填充&#xff0c;填充…

day 36 贪心算法 part05● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

一遍过。首先把区间按左端点排序&#xff0c;然后右端点有两种情况。 假设是a区间&#xff0c;b区间。。。这样排列的顺序&#xff0c;那么 假设a[1]>b[0],如果a[1]>b[1]&#xff0c;就应该以b[1]为准&#xff0c;否则以a[1]为准。 class Solution { public:static bo…

一个基于.NET Core构建的简单、跨平台、模块化的商城系统

前言 今天大姚给大家分享一个基于.NET Core构建的简单、跨平台、模块化、完全开源免费&#xff08;MIT License&#xff09;的商城系统&#xff1a;Module Shop。 商城后台管理端功能 商品&#xff1a;分类、品牌、单位、选项&#xff08;销售属性&#xff09;、属性、属性模…

人脸68关键点与K210疲劳检测

目录 人脸68关键点检测 检测闭眼睁眼 双眼关键点检测 计算眼睛的闭合程度&#xff1a; 原理: 设置阈值进行判断 实时监测和更新 拓展&#xff1a;通过判断上下眼皮重合程度去判断是否闭眼 检测嘴巴是否闭合 提取嘴唇上下轮廓的关键点 计算嘴唇上下轮廓关键点之间的距…

LangChain入门:2.OpenAPI调用ChatGPT模型

快速入门 本篇文章正式进入LangChain的编码阶段&#xff0c;今天实现的功能是使用OpenAPI调用ChatGPT模型来进行文本问答。 1. 申请OpenAPI的访问令牌 这里介绍两种获取到OpenAPI访问令牌的方式&#xff0c;大家按照自己需求进行选择&#xff0c;之后的文章我会基于第二种选…

政安晨:【深度学习神经网络基础】(二)—— 神经元与层

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 神经元是深度学习神经网络中的基本单元&#xff0c;模拟了…

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

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

DevSecOps平台架构系列-互联网企业私有化DevSecOps平台典型架构

目录 一、概述 二、私有化DevSecOps平台建设思路 2.1 采用GitOps公有云建设 2.2 采用GitOps私有云建设 2.3 总结 三、GitOps及其生态组件 3.1 采用GitOps的好处 3.1.1 周边生态系统齐全 3.1.2 便于自动化的实现 3.1.3 开发人员属性GitOps 3.2 GitOps部分生态组件介绍…

红黑树的Java实现

红黑树的Java实现 文章目录 红黑树的Java实现一、概述二、添加元素三、删除元素四、完整代码总结 一、概述 红黑树也是一种二叉平衡搜索树&#xff0c;向比与AVL树&#xff0c;是一种弱平衡树。因为AVL树是通过平衡因子&#xff0c;左右树的高度相差不能大于1来保证平衡&#…

实测梳理一下kafka分区分组的作用

清空topickafka-topics.sh --bootstrap-server localhost:9092 --delete --topic second创建分区kafka-topics.sh --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 3 --topic second发kafka-console-producer.sh --bootstrap-server localhos…

ospf实验

基础配置 如上图所示&#xff0c;按照上图所示的配置&#xff0c;俩个路由器之间按照12.12.12.X/30网段配置&#xff0c;左端的路由器和交换机之间按照192.168.1.X网段配置&#xff0c;右端的路由器和交换机之间按照192.168.2.X网段配置&#xff0c;下面的两个pc机按照所对应的…

Java 学习和实践笔记(48):怎样用二维数组来存储表格数据?

怎样用数组的方式&#xff0c;来存储下面这个表格的数据&#xff1f; 示例代码如下&#xff1a; import java.util.Arrays;public class Test001 {public static void main(String[] args) {/*object类对象是类层次结构的根。每个类都有Object作为超类。所有对象&#xff0c;包…

使用llamafile 构建本地大模型运用

安装 https://github.com/Mozilla-Ocho/llamafile 下载 大模型文件&#xff0c;选择列表中任意一个 wget https://huggingface.co/jartine/llava-v1.5-7B-GGUF/resolve/main/llava-v1.5-7b-q4.llamafile?downloadtrue https://github.com/Mozilla-Ocho/llamafile?tabre…

软件部署资源计算工具:精确评估资源需求

软件部署资源计算工具&#xff1a;精确评估资源需求 在当今快速发展的信息技术时代&#xff0c;软件部署已成为企业运营不可或缺的一部分。然而&#xff0c;一个常见的挑战是如何精确评估软件部署所需的资源。资源评估不仅关系到软件的性能和稳定性&#xff0c;还直接影响到成…

区块链食品溯源案例实现(二)

引言 随着前端界面的完成&#xff0c;我们接下来需要编写后端代码来与区块链网络进行交互。后端将负责处理前端发送的请求&#xff0c;调用智能合约的方法获取食品溯源信息&#xff0c;并将结果返回给前端。 通过前后端的整合&#xff0c;我们可以构建一个食品溯源系统&#xf…