63
技術社區[雲棲]
龐果網之尋找直方圖中麵積最大的矩形
給定直方圖,每一小塊的height由N個非負整數所確定,每一小塊的width都為1,請找出直方圖中麵積最大的矩形。
如下圖所示,直方圖中每一塊的寬度都是1,每一塊給定的高度分別是[2,1,5,6,2,3]:
那麼上述直方圖中,麵積最大的矩形便是下圖所示的陰影部分的麵積,麵積= 10單位。
請完成函數largestRectangleArea,實現尋找直方圖中麵積最大的矩形的功能,如當給定直方圖各小塊的高度= [2,1,5,6,2,3] ,返回10。
【解析】




使用一個棧來保存輸入柱狀條,每個柱狀條包含兩個信息:(1)柱狀條的高度(height);(2)柱狀條的寬度(width) 。初始寬度均為單位寬度1。
在隨後的入棧和出棧中隨時更改柱狀條的寬度。
(1)當入棧柱狀條的高度大於棧頂柱狀條的高度或者棧為空時,柱狀條入棧;如圖1
(2)當入棧柱狀條的高度小於棧頂柱狀條的高度時,柱狀條出棧,同時計算出棧的柱狀條的麵積,更新最大矩形麵積。同時更新當前柱狀條的寬度。如圖2
(3)當入棧柱狀條的高度等於棧頂柱狀條的高度時,柱狀條出棧,更新當前柱狀條寬度。如圖3
(4)如果最後棧不空,隻剩高度遞增的柱狀條。一個一個出棧,更新最大矩形麵積。每一個柱狀條出棧都要更新前一個柱狀條的寬度。如圖4
寫的不好,勿噴。
【代碼】
/*********************************
* 日期:2013-11-24
* 作者:SJF0115
* 題號: 尋找直方圖中麵積最大的矩形
* 來源:https://hero.pongo.cn/Question/Details?ID=58&ExamID=56
* 結果:AC
* 來源:龐果網
* 總結:
**********************************/
#include<iostream>
#include<stack>
#include<vector>
#include<stdio.h>
#include<malloc.h>
using namespace std;
typedef struct Rec{
int height;
int width;
}Rec;
int LargestRectangleArea(vector<int> &height){
int Max = 0,i;
int n = height.size();
//容錯處理
if(n <= 0){
return 0;
}
Rec *rec = (Rec*)malloc(sizeof(Rec)*n);
stack<Rec> stack;
//初始化
for(i = 0;i < n;i++){
rec[i].height = height[i];
rec[i].width = 1;
}
for(i = 0;i < n;i++){
int h = rec[i].height;
//如果棧空或者當前高度大於棧頂的矩形高度的時候就壓入棧
if(stack.empty() || h > stack.top().height){
stack.push(rec[i]);
}
else{
int preWidth = 0;
//小於棧頂的矩形高度就彈出棧,更新最大的矩形麵積
while(!stack.empty() && h < stack.top().height){
rec[i].width += stack.top().width;
//當前麵積
int currentMax = stack.top().height * (stack.top().width + preWidth);
//更新最大值
if(Max < currentMax){
Max = currentMax;
}
preWidth += stack.top().width;
//出棧
stack.pop();
}
//等於棧頂的矩形高度
while(!stack.empty() && h == stack.top().height){
rec[i].width += stack.top().width;
stack.pop();
}
//棧空
if(stack.empty() || h > stack.top().height){
stack.push(rec[i]);
}
}
}
//最後棧中隻剩遞增的序列
int width = 0;
while(!stack.empty()){
int currentMax = stack.top().height * (stack.top().width + width);
if(currentMax > Max){
Max = currentMax;
}
width += stack.top().width;
stack.pop();
}
return Max;
}
int main(){
int i,n,Max,num;
while(scanf("%d",&n) != EOF){
vector<int> height;
for(i = 0;i < n;i++){
scanf("%d",&num);
height.push_back(num);
}
Max = LargestRectangleArea(height);
printf("%d\n",Max);
}
return 0;
}
【方法二】
【解析】
設柱狀圖為非負整數數組A, 則最大矩形的高度必定是數組的某一項height[i]。
設f(i) 為以數組第i項的高度為矩形高度時矩形的最大寬度,則最大矩形為max{f(i)*height[i]} (0 <= i < n)
f(i)本身無法動態規劃,但若將f(i)拆成左右兩部分,則很容易動態規劃求解
令left(i)為以數組第i項為矩形高度時矩形左側最大寬度,
right(i)為以數組第i項為矩形高度時矩形右側最大寬度,
則f(i) = left(i) + right(i) - 1
【代碼】
/*********************************
* 日期:2013-11-25
* 作者:SJF0115
* 題號: 尋找直方圖中麵積最大的矩形
* 來源:https://hero.pongo.cn/Question/Details?ID=58&ExamID=56
* 結果:AC
* 來源:龐果網
* 總結:
**********************************/
#include <stdio.h>
int left[100001],right[100001];
int largestRectangleArea(const int *height,int n) {
int Max = 0,i,j;
//容錯處理
if(height == NULL || n <= 0){
return 0;
}
left[0] = 1;
right[n-1] = 1;
//以數組第i項為矩形高度時矩形左側最大寬度
for(i = 1;i < n;i++){
//初始為單位寬度1
left[i] = 1;
for(j = i-1;j >= 0;){
if(height[i] <= height[j]){
left[i] += left[j];
//跳到下一個比較對象
j -= left[j];
}
else{
break;
}
}
//printf("第%d項左最大寬度:%d\n",i+1,left[i]);
}
//以數組第i項為矩形高度時矩形右側最大寬度
for(i = n-2;i >= 0;i--){
//初始為單位寬度1
right[i] = 1;
for(j = i+1;j < n;){
if(height[i] <= height[j]){
right[i] += right[j];
//跳到下一個比較對象
j += right[j];
}
else{
break;
}
}
//printf("第%d項右最大寬度:%d\n",i+1,right[i]);
}
for(i = 0;i < n;i++){
int currentMax = (left[i] + right[i] - 1) * height[i];
if(Max < currentMax){
Max = currentMax;
}
}
return Max;
}
//start 提示:自動閱卷起始唯一標識,請勿刪除或增加。
int main()
{
int height[] = {1,2,3,4,3,4,3,2,1};
int max = largestRectangleArea(height,9);
printf("%d\n",max);
return 0;
}
//end //提示:自動閱卷結束唯一標識,請勿刪除或增加。
【測試數據】
{1,2,3,4,3,4,3,2,1} 結果: 15
{3,4,5,6} 結果:12
{2,1,2,1,2,1} 結果:6
{2,1,5,6,2,3}結果:10
{2, 1, 4, 5, 1, 3, 3, 1, 2} 結果:9
最後更新:2017-04-03 14:54:25
上一篇:
給出任意一個正整數,算出大於它的最小不重複數——最高效[2014百度筆試題]
下一篇:
龐果網之楊輝三角的變形
struts中接收數組的表單和ajax兩種形式
阿裏公布百家售假企業黑名單,還挖出了千餘造假工廠
GUI Design Studio 使用教程
讓ATM瘋狂吐錢的黑客死了
IBM WebSphere Application Server V6.1 Fix Pack 37於2011.04.04發布
[JAVA軟件工程師-麵試寶典-2013最新版]
VS2010 Tips: How to change Local Help Library path
在32位的Ubuntu 11.04中為Android NDK r6編譯FFmpeg0.8.1版-Android中使用FFmpeg媒體庫(一)
java.lang.ClassNotFoundException: org.apache.catalina.loader.DevLoader
理解JAVA的傳值方式