【單調棧】-----【小A的柱狀圖】

小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 r?l?1 來計算寬度,而必須使用前綴和數組進行區間寬度的快速求解。

二、解法思路

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,r?1] 中的總寬度。

所以,以第 i i i 根柱子為高、左右能擴展到 [ L i + 1 , R i ? 1 ] [L_i+1, R_i-1] [Li?+1,Ri??1],總寬度為:

寬度 \text{寬度} 寬度= sum [ R i ? 1 ] \text{sum}[R_i - 1] sum[Ri??1] - 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[Ri??1]?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 以及相關分析技術來簡化和…