小A的柱状图

题目链接

题目描述

柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为 a [ i ] a[i] a[i],每个矩形的高度是 h [ i ] h[i] h[i],现在小A只想知道,在这个图形里面包含的最大矩形面积是多少。
在这里插入图片描述


输入描述

  • 一行一个整数 N N N,表示长方形的个数
  • 接下来一行 N N N 个整数表示每个长方形的宽度
  • 接下来一行 N N N 个整数表示每个长方形的高度

输出描述

一行一个整数,表示最大的矩形面积


示例 1

输入

7
1 1 1 1 1 1 1
2 1 4 5 1 3 3

输出

8

说明

样例如图所示,包含的最大矩形面积是 8。


数据范围

  • 1 ≤ n ≤ 10 6 1 \leq n \leq 10^6 1n106
  • 1 ≤ a [ i ] ≤ 100 1 \leq a[i] \leq 100 1a[i]100
  • 1 ≤ h [ i ] ≤ 10 9 1 \leq h[i] \leq 10^9 1h[i]109

题解(单调栈 + 前缀和)

单调栈原理见本文
前置题目见本文


一、问题抽象

我们的问题可以等价于:

给定若干个高度不等、宽度也不等的矩形,从中选择一个连续的子区间,使得该区间中所有矩形的高度都不小于某个 h h h,从而形成面积最大的矩形区域。

与经典的柱状图最大矩形问题不同点在于:

  • 每个柱子的宽度不再是固定值 1 1 1,而是任意正整数 a [ i ] a[i] a[i]
  • 所以我们不能用下标差 r − l − 1 r - l - 1 rl1 来计算宽度,而必须使用前缀和数组进行区间宽度的快速求解。

二、解法思路

Step 1:计算每个柱子的左边界 L i L_i Li

对于每根柱子 i i i,我们希望找到其左边第一个比它矮的柱子的位置,记为 L i L_i Li

这可以使用单调递增栈完成,栈中存放的是柱子下标,确保栈顶元素对应的柱子高度严格递增。

Step 2:计算每个柱子的右边界 R i R_i Ri

同理,从右往左遍历,找出每根柱子右侧第一个比它矮的柱子位置 R i R_i Ri

此时也用单调递增栈,方向相反,栈中依然维护下标,快速剔除不可能作为边界的柱子。

注意:如果某一侧没有更矮柱子,则左边界设为 0 0 0,右边界设为 n + 1 n+1 n+1,表示整个图形的边界。


Step 3:使用前缀和计算宽度

由于每根柱子的宽度不同,我们构造一个前缀和数组 sum[i]

  • 表示前 i i i 个矩形的总宽度;
  • 可以用来快速求任意区间 [ l + 1 , r − 1 ] [l+1, r-1] [l+1,r1] 中的总宽度。

所以,以第 i i i 根柱子为高、左右能扩展到 [ L i + 1 , R i − 1 ] [L_i+1, R_i-1] [Li+1,Ri1],总宽度为:

宽度 \text{宽度} 宽度= sum [ R i − 1 ] \text{sum}[R_i - 1] sum[Ri1] - sum [ L i ] \text{sum}[L_i] sum[Li]


Step 4:计算所有矩形面积,取最大值

以每根柱子为“最矮柱子”计算可扩展的矩形面积:

面积 i = h i × ( sum [ R i − 1 ] − sum [ L i ] ) \text{面积}_i = h_i \times (\text{sum}[R_i - 1] - \text{sum}[L_i]) 面积i=hi×(sum[Ri1]sum[Li])

最终在所有柱子中取最大面积即可。


三、完整代码

#include <bits/stdc++.h>
using namespace std;
#define int long long// 函数 lmin:求每个位置左侧第一个比它矮的位置(单调递增栈)
vector<int> lmin(const vector<int>& nums, int n)
{// 定义单调栈,栈中存放的是下标,保持栈内高度递增stack<int> value;// ender[i] 表示 i 左边第一个比 nums[i] 小的位置(下标)// 若无更矮柱子,则设置为 0vector<int> ender(n + 1, 0);// 从左到右扫描每个位置for (int i = 1; i <= n; i++){// 1.弹出栈顶元素,直到遇到比当前高度小的位置为止while (!value.empty() && nums[value.top()] >= nums[i]){value.pop();}// 2.若栈为空,说明左侧无更矮柱子,设置为 0// 否则栈顶即为左边第一个比当前柱子矮的位置ender[i] = value.empty() ? 0 : value.top();// 3.当前柱子入栈value.push(i);}// 返回左边界数组return ender;
}// 函数 rmin:求每个位置右侧第一个比它矮的位置(单调递增栈)
vector<int> rmin(const vector<int>& nums, int n)
{// 定义单调栈,栈中存放的是下标,保持栈内高度递增stack<int> value;// ender[i] 表示 i 右边第一个比 nums[i] 小的位置(下标)// 若无更矮柱子,则设置为 n+1(越界值)vector<int> ender(n + 1, 0);// 从右到左扫描每个位置for (int i = n; i >= 1; i--){// 1.弹出栈顶元素,直到遇到比当前高度小的位置为止while (!value.empty() && nums[value.top()] >= nums[i]){value.pop();}// 2.若栈为空,说明右侧无更矮柱子,设置为 n+1// 否则栈顶即为右边第一个比当前柱子矮的位置ender[i] = value.empty() ? n + 1 : value.top();// 3.当前柱子入栈value.push(i);}// 返回右边界数组return ender;
}signed main()
{// 读取矩形数量int n;cin >> n;// wei[i] 表示第 i 个矩形的宽度// hei[i] 表示第 i 个矩形的高度vector<int> wei(n + 1);vector<int> hei(n + 1);// 读取每个矩形的宽度(下标从 1 开始)for (int i = 1; i <= n; i++){cin >> wei[i];}// 读取每个矩形的高度for (int i = 1; i <= n; i++){cin >> hei[i];}// 使用前缀和来快速求出任意区间的总宽度// sum[i] 表示前 i 个矩形的总宽度,用于快速计算任意区间宽度vector<int> sum(n + 1, 0);// 初始化前缀和sum[1] = wei[1];// 构造前缀和数组for (int i = 2; i <= n; i++){sum[i] = sum[i - 1] + wei[i];}// 计算每个位置左侧第一个比它矮的柱子下标vector<int> ender1 = lmin(hei, n);// 计算每个位置右侧第一个比它矮的柱子下标vector<int> ender2 = rmin(hei, n);// 记录最大矩形面积int ans = 0;// 遍历每个柱子,考虑以它为高的最大矩形for (int i = 1; i <= n; ++i){// 左边界(不包含)int l = ender1[i];// 右边界(不包含)int r = ender2[i];// 当前柱子可扩展的矩形区域是区间 [l + 1, r - 1]// 宽度为 sum[r - 1] - sum[l]int width = sum[r - 1] - sum[l];// 面积 = 高度 × 宽度int area = hei[i] * width;// 更新最大面积ans = max(ans, area);}// 输出结果cout << ans << endl;return 0;
}

四、时间复杂度分析

  • 单调栈找左右边界时间复杂度为 O ( n ) O(n) O(n)
  • 构造前缀和数组复杂度 O ( n ) O(n) O(n)
  • 遍历计算所有面积复杂度 O ( n ) O(n) O(n)

所以整体时间复杂度为:

O ( n ) O(n) O(n)

空间复杂度同样是 O ( n ) O(n) O(n),用于存储前缀和与边界数组。


五、总结

本题是「最大矩形面积」问题的变种,处理了宽度不等的情况。

解题核心:

  1. 单调栈快速寻找左右边界,避免暴力;
  2. 用前缀和代替下标差求区间宽度;
  3. 每根柱子作为“最矮的”核心,计算能扩展的最大矩形。

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

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

相关文章

MySQL 索引优化与慢查询优化:原理与实践

MySQL是一个广泛使用的关系型数据库管理系统&#xff0c;优化MySQL的性能对于保证应用的高效运行至关重要。本文将详细介绍MySQL索引优化与慢查询优化的原理和实践方法。 一、MySQL索引优化 1.1 索引的基本概念 索引是一种用于提高数据库查询速度的数据结构。常见的索引类型…

【AS32系列MCU调试教程】应用开发:基于AS32芯片的流水灯功能实现

摘要&#xff1a; 本文以国科安芯的AS32系列MCU芯片为例&#xff0c;聚焦于基于 AS32 芯片的流水灯功能开发&#xff0c;深入阐述了开发环境搭建、工程配置以及调试等关键环节。通过详尽的实验过程与结果分析&#xff0c;旨在为相关领域技术人员提供一套系统、高效且成本可控的…

爬虫001----介绍以及可能需要使用的技术栈

首先1️⃣。。。全篇使用的技术栈当然是python了&#xff0c;毕竟作为一名点点点工程师&#xff0c;实际工作中做测试开发用的也是python&#xff0c;毕竟测试框架么&#xff0c;不需要什么"速度"。也会一点点cpp和js&#xff0c;但不多。什么&#xff1f;你说go和ja…

Java 中基于条件动态决定字段参与分组的实现方法

在 Java 的 Stream API 中&#xff0c;Collectors.groupingBy()方法为数据分组提供了强大的支持。通过它&#xff0c;我们可以轻松地将集合中的元素按照某个属性进行分组&#xff0c;比如按照商品类别、日期等。然而&#xff0c;在实际业务场景中&#xff0c;有时需要根据特定条…

AppBarLayout+ CoordinatorLayout,ViewPager2为什么不会覆盖AppBarLayout

<?xml version"1.0" encoding"utf-8"?> <layout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http://schemas.android.com/tools&quo…

【群体智能优化算法系列 】一 粒子群算法 (Particle Swarm Optimization, PSO)

【群体智能优化算法系列 】一 粒子算法 一&#xff1a;前言二&#xff1a;算法原理2.1 核心思想2.2 PSO核心公式​2.3 PSO算法流程图 三&#xff1a;python实现 二维Rastrigin函数 最低点检索例子参考 一&#xff1a;前言 粒子群算法是由Kennedy和Eberhart在1995年提出的一种基…

Jupyter notebook调试:设置断点运行

写了一段小代码&#xff0c;主要是用来测试一段序列的k均值聚类效果&#xff1b; 中间想到debug一下&#xff0c;但是想到自己似乎从来没有正式地接触过jupyter notebook中地debug&#xff0c;平时也只是多开几个cell&#xff0c;然后在其他cell中复制粘贴部分代码&#xff0c…

[12-2] BKP备份寄存器RTC实时时钟 江协科技学习笔记(14个知识点)

1 2 3 4 5 6 7 8 RTC是“Real-Time Clock”的缩写&#xff0c;中文意思是“实时时钟”。这是一种在电子设备中使用的时钟&#xff0c;它能够提供准确的时间信息&#xff0c;即使在设备断电的情况下也能继续运行&#xff0c;因为它通常由一个小型电池供电。RTC广泛应用于计算机…

优化给AI的“提问技巧”(提示工程),让大型语言模型(比如GPT)更好地扮演“心理治疗助手”的角色

优化给AI的“提问技巧”(提示工程),让大型语言模型(比如GPT)更好地扮演“心理治疗助手”的角色 尤其是在“问题解决疗法”(PST)中帮助 caregivers(家庭护理者)缓解焦虑、疲劳等心理症状。以下是核心内容的通俗解读: 一、研究背景:AI当心理医生靠谱吗? 现状:全球…

Java的lambda表达式应用

Lambda表达式是Java 8引入的一项强大特性&#xff0c;它允许以更加简洁的方式表示匿名函数。Lambda表达式不仅让代码更加简洁、清晰&#xff0c;而且为函数式编程提供了有力支持&#xff0c;从而提升了Java语言的表达能力。 本文主要讲解lambda应用stream处理集合的应用。 1、…

云原生/容器相关概念记录

文章目录 网络与虚拟化技术云平台与架构容器与编排容器网络方案性能优化与工具硬件与协议 网络与虚拟化技术 P4可编程网关 P4: Programming Protocol-independent Packet Processors一种基于P4语言的可编程网络设备&#xff0c;支持自定义数据包处理逻辑。P4可编程技术详解&am…

[C++] traits机制

文章目录 C之type_traitsis_floating_point<T> ..的使用std::enable_if<T>::type的使用std::remove_cv 如何自定义traits C之type_traits is_floating_point …的使用 一般在定义打印模板函数的时候&#xff0c;当我们用printf进行终端日志打印&#xff0c;需要根…

OpenCV 视频处理与保存

一、知识点 1、VideoCapture类 (1)、用于从视频文件、摄像机或图像序列中捕获视频帧。 (2)、构造函数 VideoCapture(const String & filename, int apiPreference CAP_ANY) a、filename可以是视频文件的名称(例如"video.avi")&#xff0c;可以是图…

【Leetcode】字符串之二进制求和、字符串相乘

文章目录 算法原理二进制求和题目链接题目描述解题思路代码 字符串相乘题目链接题目描述解题思路代码 算法原理 这两道题都是属于算法里一种经典题型&#xff1a;高精度加/减/乘/除法&#xff0c;需要我们模拟加/减/乘/除 列竖式运算。 二进制求和 题目链接 题目链接 题目描…

MongoDB:索引

目录 1、索引数据结构&#xff1a;B-树 2、索引类型 2.1 单字段索引 2.2 复合索引&#xff08;最重要&#xff01;&#xff09; 2.3 多键索引&#xff08;数组字段&#xff09; 2.4 地理空间索引 2.5 全文索引 2.6 哈希索引&#xff08;分片专用&#xff09; 2.7 TTL …

【大模型】Transformer架构完全解读:从“盲人摸象“到“通晓万物“的AI进化论

&#x1f916; Transformer架构完全解读&#xff1a;从"盲人摸象"到"通晓万物"的AI进化论 —— 一位大模型探索者的技术日记 ☕ 第一章&#xff1a;为什么说Transformer是AI界的"蒸汽机革命"&#xff1f; 1.1 从RNN到Transformer&#xff1a;…

JavaEE:使用JMeter进行接口并发测试

一、下载与安装&#xff1a; 1.下载apache-jmeter-5.6.3.zip&#xff1a; https://jmeter.apache.org/download_jmeter.cgi 2.解压到D:\Program Files\apache-jmeter-5.6.3目录 3.添加JDK环境配置到D:\Program Files\apache-jmeter-5.6.3\bin\jmeter.bat文件开头&#xff1…

【笔记】MSYS2 的 MinGW64 环境中正确安装 Python 相关环境管理工具 (Poetry、Virtualenv、Pipenv 和 UV)

MSYS2 环境配置与 Python 项目依赖管理笔记_msys更新python-CSDN博客 【技术笔记】MSYS2 指定 Python 版本安装方案_pacman -u 安装指定版本-CSDN博客 更多关于 MSYS2 开发环境的配置&#xff0c;请查看往期笔记。 简介 本笔记将记录我们在 MSYS2 的 MinGW64 环境中安装 Pytho…

ubuntu添加域名解析服务器地址

在 Ubuntu 中配置域名解析主要有两种方式&#xff1a;静态修改 /etc/hosts 文件 和 动态修改 DNS 解析服务器配置。以下是详细操作指南&#xff1a; 建议优选:二、永久方案&#xff1a;修改 DNS 解析服务&#xff08;推荐&#xff09;中的方法1 一、临时方案&#xff1a;修改…

通过 AIOps 、生成式 AI 和机器学习实现更智能的可观测性

支持 AIOps 的理由 人工智能运维&#xff08;AIOps&#xff09;是将人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&#xff09;和分析技术应用于提升 IT 运维团队日常工作的过程。简单来说&#xff0c;AIOps 是软件系统通过 AI 和 ML 以及相关分析技术来简化和…