【八十五】【算法分析与设计】单调栈的全新版本,两个循环维护左小于和右小于信息,84. 柱状图中最大的矩形,85. 最大矩形

84. 柱状图中最大的矩形

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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= heights.length <=10(5)

  • 0 <= heights[i] <= 10(4)

1.

思路就是以每一个位置的柱状图的高度作为矩形的高,然后看以这个高能够扩多长的底,计算这个情况下的面积.

问题被划分为几个小的部分,以每一个高度为高去计算.

2.

单调栈存储左小于,右小于.

老旧的单调栈写法是在元素出栈的时候维护数据.

但是发现这样特别浪费内存,有的时候还需要给栈开辟二维空间处理相同的数据.

这种做法实在是太低效了,并且在这道题目的提交结果居然超出了题目的内存.

3.

全新的版本,只用一个单独的栈就可以完成重复元素或者不重复元素.

首先我们需要确定我们的目的是什么,是填写信息每一个元素左小于,右小于的信息.

老旧版本是在出栈的时候维护信息,全新版本是在入栈的时候维护信息.

每一个元素入栈的时候,维护栈内单调性,然后维护入栈元素左小于或者右小于信息.

对于每一个入栈元素,栈内一定是单调性,此时一定可以找到左小于或者右小于.

老旧版本

 
class Solution {
public:
    vector<int> arr;
    int n;
    int ret;
    using p = pair<int, int>;
    vector<p> p_m;
    vector<vector<int>> st;

    void init() {
        n = arr.size();
        p_m.clear(), p_m.resize(n);
    }
    void solve() {
        int i = 0;
        while (1) {
            if (i >= n)
                break;
            if (st.empty())
                st.push_back({i});
            else {
                auto top = st.back();
                while (1) {
                    if (arr[i] >= arr[top[0]])
                        break;
                    st.pop_back();
                    for (auto& x : top) {
                        p_m[x].second = i;
                        p_m[x].first = st.empty() ? -1 : st.back().back();
                    }
                    if (st.empty())
                        break;
                    else
                        top = st.back();
                }
                if (st.empty())
                    st.push_back({i});
                else {
                    if (arr[st.back()[0]] == arr[i])
                        st.back().push_back(i);
                    else
                        st.push_back({i});
                }
            }
            i++;
        }

        while(1){
            if(st.empty())break;
            auto top=st.back();
            st.pop_back();
            for(auto& x:top){
                p_m[x].second=n;
                p_m[x].first=st.empty()?-1:st.back().back();
            }
        }

        for(int i=0;i<n;i++){
            ret=max(ret,arr[i]*(p_m[i].second-p_m[i].first-1));
        }
    }

    int largestRectangleArea(vector<int>& _heights) {
        arr = _heights;
        init(), solve();
        return ret;
    }
};

全新版本

 
class Solution {
public:
    vector<int> arr;
    //下标-元素
    int n;
    //元素的个数
    int ret;
    //记录结果信息
    using p = pair<int, int>;
    vector<p> p_m;
    //记录每一个元素左小于,右小于的信息
    vector<int> st;
    //vector模拟栈
    void init() {
        n = arr.size();
        p_m.clear(), p_m.resize(n);
    }
    void solve() {
    //首先维护每一个元素的左小于的信息
        for (int i = 0; i < n; i++) {
            while (1) {
            //维护栈内单调性,严格的小到大
                if (st.empty())
                    break;
                if (arr[st.back()] < arr[i])
                    break;
                st.pop_back();
                //出栈,因为此时他们都不可能再作为某元素的左小于了.
            }
            //维护入栈元素的左小于信息
            p_m[i].first = st.empty() ? -1 : st.back();
            st.push_back(i);
            //入栈
        }
        
        st.clear();
        //栈清空
        
        //维护所有元素的右小于信息
        //此时必须是从后往前填写,因为对于j位置我需要找右小于,那么右边所有元素需要入栈并且栈保持单调
        for (int i = n - 1; i >= 0; i--) {
            while (1) {
                if (st.empty())
                    break;
                if (arr[st.back()] < arr[i])
                    break;
                st.pop_back();
            }
            p_m[i].second = st.empty() ? n : st.back();
            //维护右小于信息
            st.push_back(i);
        }

        for (int i = 0; i < n; i++) {
            ret = max(ret, arr[i] * (p_m[i].second - p_m[i].first - 1));
        }
    }

    int largestRectangleArea(vector<int>& _heights) {
        arr = _heights;
        init(), solve();
        return ret;
    }
};

85. 最大矩形

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

示例 1:

 
 

class Solution { public: vector<int> arr; //下标-元素 int n; //元素的个数 int ret; //记录结果信息 using p = pair<int, int>; vector<p> p_m; //记录每一个元素左小于,右小于的信息 vector<int> st; //vector模拟栈 void init() { n = arr.size(); p_m.clear(), p_m.resize(n); } void solve() { //首先维护每一个元素的左小于的信息 for (int i = 0; i < n; i++) { while (1) { //维护栈内单调性,严格的小到大 if (st.empty()) break; if (arr[st.back()] < arr[i]) break; st.pop_back(); //出栈,因为此时他们都不可能再作为某元素的左小于了. } //维护入栈元素的左小于信息 p_m[i].first = st.empty() ? -1 : st.back(); st.push_back(i); //入栈 } st.clear(); //栈清空 //维护所有元素的右小于信息 //此时必须是从后往前填写,因为对于j位置我需要找右小于,那么右边所有元素需要入栈并且栈保持单调 for (int i = n - 1; i >= 0; i--) { while (1) { if (st.empty()) break; if (arr[st.back()] < arr[i]) break; st.pop_back(); } p_m[i].second = st.empty() ? n : st.back(); //维护右小于信息 st.push_back(i); } for (int i = 0; i < n; i++) { ret = max(ret, arr[i] * (p_m[i].second - p_m[i].first - 1)); } } int largestRectangleArea(vector<int>& _heights) { arr = _heights; init(), solve(); return ret; } };

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]] 输出:6 解释:最大矩形如上图所示。

示例 2:

输入:matrix = [["0"]] 输出:0

示例 3:

输入:matrix = [["1"]] 输出:1

提示:

  • rows == matrix.length

  • cols == matrix[0].length

  • 1 <= row, cols <= 200

  • matrix[i][j]'0''1'

1.

思路是每一行看作是柱状图的开始,那么题目完全转化为84. 柱状图中最大的矩形.

用dp记录每一个位置的柱状图高度.

每一行都计算一次,ret记录所有情况的最大值即可.

2.

入栈的时候维护信息.

一个循环维护左信息,一个循环维护右信息.

 
class Solution {
public:
    vector<vector<char>> arr;
    //arr表示矩形原始数据
    int row, col;
    //row和col表示矩形的行和列数
    int ret;
    //ret记录结果数据
    vector<vector<int>> dp;
    //dp记录所有位置的柱状图高度
    vector<vector<int>> p_min;
    //存储每一行的柱状图的左小于右小于信息
    vector<int> st;
    //模拟栈
    void init() {
        row = arr.size(), col = arr[0].size();
        dp.clear(), dp.resize(row, vector<int>(col));
        //计算dp值
        for (int j = 0; j < col; j++) {
            for (int i = 0; i < row; i++) {
                if (arr[i][j] == '1')
                    dp[i][j] = 1 + (i - 1 >= 0 ? dp[i - 1][j] : 0);
                else
                    dp[i][j] = 0;
            }
        }
        p_min.clear(), p_min.resize(col, { 0, 0 });
        //用{}大括号初始化vector,长度小的时候很方便
        
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                cout << dp[i][j] << " ";
            }
            cout << endl;
        }
        //看一下dp值有没有计算计算错误
    }
    void solve() {
    //正式开始解题
        for (int i = 0; i < row; i++) {
        //首先遍历每一行,表示每一个柱状图
            p_min.clear(), p_min.resize(col, { 0, 0 });
            st.clear();
            //初始化左小于右小于信息
            //初始化栈
            
            for (int j = 0; j < col; j++) {
            //先维护当前行的左小于信息
                while (1) {
                    if (st.empty())break;
                    if (dp[i][j] > dp[i][st.back()])break;
                    st.pop_back();
                }
                p_min[j][0] = st.empty() ? -1 : st.back();
                //维护当前j位置左小于信息
                st.push_back(j);
                //入栈
            }
            st.clear();
            //栈清空
            
            //维护右小于信息
            for (int j = col - 1; j >= 0; j--) {
                while (1) {
                    if (st.empty())break;
                    if (dp[i][j] > dp[i][st.back()])break;
                    st.pop_back();
                }
                p_min[j][1] = st.empty() ? col : st.back();
                st.push_back(j);
            }

            //此时完成当前行的左小于右小于信息维护
            //计算此时可能的矩形面积
            for (int j = 0; j < col; j++) {
                ret = max(ret, (p_min[j][1] - p_min[j][0] - 1) * dp[i][j]);
            }

            for (int j = 0; j < col; j++) {
                cout << p_min[j][0] << " " << p_min[j][1] << " ";
            }
            cout << endl;
            //打印看一下有没有问题
        }
    }

    int maximalRectangle(vector<vector<char>>& _matrix) {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
        arr = _matrix;
        init();
        solve();
        return ret;
    }
};

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go的安装与配置

安装 https://go.dev/dl/ 以Windows上安装为例&#xff1a; 下一步下一步&#xff0c;记住安装位置 安装完成后 win rcmd 键入go version检查是否安装成功 配置 Go 工作区 Go 在组织项目文件方面与其他编程语言不同。 Go 是在工作区的概念下工作的。但是从版本 1.11 开始&…

docker-compose部署java项目

docker-compose是定义和运行多容器的工具。换句话说就是通过配置yml文件来运行容器&#xff0c;简化了每次输入docker run等命令&#xff0c;把这些命令配置在yml文件统一管理&#xff0c;而且可以用一个yml文件一次启动多个容器&#xff0c;启动时还可以设置各个容器的依赖关系…

远程开机与远程唤醒BIOS设置

远程开机与远程唤醒BIOS设置 在现代计算机应用中&#xff0c;远程管理和控制已成为许多企业和个人的基本需求。其中&#xff0c;远程开机和远程唤醒是两项非常实用的功能。要实现这些功能&#xff0c;通常需要在计算机的BIOS中进行一些特定的设置。以下是对远程开机和远程唤醒…

如何判断nat网络?如何内网穿透

大家都清楚&#xff0c;如果你想开车&#xff0c;就必须要给车上一个牌照&#xff0c;随着车辆越来越多&#xff0c;为了缓解拥堵&#xff0c;就需要摇号&#xff0c;随着摇号的人数越来越多&#xff0c;车牌对于想开车的人来说已经成为奢望。在如今的IPv4时代&#xff0c;我们…

全自动减压器法二氧化碳气容量测试仪:饮料行业的革新与未来

全自动减压器法二氧化碳气容量测试仪&#xff1a;饮料行业的革新与未来 一、引言 在追求品质与效率的现代饮料生产领域&#xff0c;全自动减压器法二氧化碳气容量测试仪凭借其高精度、高效率及无人工干预的显著优势&#xff0c;正逐渐成为行业的标杆。特别是在碳酸饮料的生产中…

USB系列五:USB设备配置(重要)

在USB总线接口协议中&#xff0c;对于USB外部设备功能特征是通过端点&#xff08;Endpoint&#xff09;、配置&#xff08;Configuration&#xff09;和接口&#xff08;Interface&#xff09;来描述的&#xff0c;这些就是典型的USB描述符。 USB主机通过设备请求来读取外部设…

并行执行线程资源管理方式——《OceanBase 并行执行》系列 3

在某些特定场景下&#xff0c;由于需要等待线程资源&#xff0c;并行查询会遇到排队等待的情况。本篇博客将介绍如何管理并行执行线程资源&#xff0c;以解决这种问题。 《OceanBase并行执行》系列的内容分为七篇博客&#xff0c;本篇是其中的第三篇。前2篇如下&#xff1a; 一…

分布式与一致性协议之Quorum NWR算法

Quorum NWR算法 概述 不知道你在工作中有没有遇到过这样的事情:你开发实现了一套AP型分布式系统&#xff0c;实现了最终一致性&#xff0c;且业务接入后运行正常&#xff0c;一切看起来都那么美好。 可是突然有同事说&#xff0c;我们要拉这几个业务的数据做实时分析&#xf…

AXI4读时序在AXI Block RAM (BRAM) IP核中的应用

在本文中将展示描述了AXI从设备&#xff08;slave&#xff09;AXI BRAM Controller IP核与Xilinx AXI Interconnect之间的读时序关系。 1 Single Read 图1展示了一个从32位BRAM&#xff08;Block RAM&#xff09;进行AXI单次读取操作的时序示例。 图1 AXI 单次读时序图 在该…

webpack如何自定义一个loader

我们在使用脚手架的搭建项目的时候往往都会帮我们配置好所需的loader&#xff0c;接下来讲一下我们要如何自己写一个loader应用到项目中&#xff08;完整代码在最后&#xff09; 1. 首先搭建一个项目并找到webpack配置文件&#xff08;webpack.config.js&#xff09; 在modul…

clickhouse学习笔记06

ClickHouse的建表和引擎选择思路讲解 ClickHouse的常见注意事项和异常问题排查 ClickHouse高性能查询原因剖析-稀疏索引 ClickHouse高性能写入剖析-LSM-Tree存储结构

嵌入式开发十:STM32开发基础入门知识补充

本篇博客主要是针对前面STM32入门基础知识的补充&#xff0c;为后面的真正开发学习做好准备。 目录 一、IO 引脚复用器和映射 1.1 引脚复用的概念 1.2 如何设计实现复用 1.3 复用功能固件库配置过程 二、STM32 NVIC 中断优先级管理 2.1 NVIC中断优先级管理结构体介绍 …

力扣每日一题-统计已测试设备-2024.5.10

力扣题目&#xff1a;统计已测试设备 题目链接: 2960.统计已测试设备 题目描述 代码思路 根据题目内容&#xff0c;第一感是根据题目模拟整个过程&#xff0c;在每一步中修改所有设备的电量百分比。但稍加思索&#xff0c;发现可以利用已测试设备的数量作为需要减少的设备电…

16地标准化企业申请!安徽省工业和信息化领域标准化示范企业申报条件

安徽省工业和信息化领域标准化示范企业申报条件有哪些&#xff1f;合肥市 、黄山市 、芜湖市、马鞍山、安庆市、淮南市、阜阳市、淮北市、铜陵市、亳州市、宣城市、蚌埠市、六安市 、滁州市 、池州市、宿州市企业申报安徽省工业和信息化领域标准化示范企业有不明白的可在下文了…

机器学习各个算法的优缺点!(上篇) 建议收藏。

下篇地址&#xff1a;机器学习各个算法的优缺点&#xff01;&#xff08;下篇&#xff09; 建议收藏。-CSDN博客 今天有朋友聊起来&#xff0c;机器学习算法繁多&#xff0c;各个算法有各个算法的特点。 以及在不同场景下&#xff0c;不同算法模型能够发挥各自的优点。 今天…

Java之异常处理

一、认识异常 1.异常的概念 在 Java 中&#xff0c;将程序执行过程中发生的不正常行为称为异常。。比如之前写代码时经常遇到的&#xff1a; 1. 算术异常 System.out.println(10 / 0); // 执行结果 Exception in thread "main" java.lang.ArithmeticException: /…

深化产教融合,泰迪智能科技助力西南林业大学提质培优

2024年5月7日&#xff0c;泰迪智能科技昆明分公司院校部总监查良红和数据部负责人余雄亮赴西南林业大学理学院就工作室共建事宜进行交流会谈。西南林业大学理学院院长张雁、党委副书记魏轶、副院长谢爽、就业负责人罗丽及学生代表参与本次交流会。 会议伊始&#xff0c;谢副院长…

FPGA HDMI Sensor无线航模摄像头

FPGA方案&#xff0c;接收摄像头sensor 图像数据后&#xff0c;通过HDMI输出到后端 客户应用&#xff1a;无线航模摄像头 主要特性&#xff1a; 1.支持2K以下任意分辨率格式 2.支持多种型号sensor 3.支持自适应摄像头配置&#xff0c;并补齐输出时序 4.可定制功能&#xff…

休斯《公共管理导论》第4版教材精讲视频网课+考研真题讲解

内容简介 本课程是休斯《公共管理导论》&#xff08;第4版&#xff09;精讲班&#xff0c;为了帮助参加研究生招生考试指定考研参考书目为休斯《公共管理导论》&#xff08;第4版&#xff09;的考生复习专业课&#xff0c;我们根据教材和名校考研真题的命题规律精心讲解教材章节…

HR招聘面试测评,如何判断候选人的创新能力?

创新能力代表着一个人的未来发展潜力&#xff0c;创新能力突出的人&#xff0c;未来的上限就可能更高。而对于一个公司而言&#xff0c;一个具有创新能力的员工&#xff0c;会给公司带来新方案&#xff0c;新思路&#xff0c;对公司的长远发展拥有着十分积极的作用。 而在挑选…