转载请注明出处:https://blog.csdn.net/yyying2016/article/details/80119171
一 题目:
Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]
.
The largest rectangle is shown in the shaded area, which has area = 10
unit.
Example:
Input: [2,1,5,6,2,3] Output: 10
二 分析
1、如果用暴力解法的话,对每个柱子遍历一遍其左右一段连续且比他高的柱子,复杂度为O(n^2),由于该题的数据太大,会导致TLE。
2、如果用一个栈来维护的话,可以实现O(n)的解法,想法的中心就是从左到右着解决每一个“山峰”,同时记录下当前最大的矩形面积,具体思路如下:
建立一个空栈,用来记录一个递增的柱体的下标。
再建立一个int类型的数ans,用来记录目前所得到的最大值。
(1) 先对柱子的vector进行遍历一遍:
① 如果栈为空,或者当前柱子高度高于/等于栈顶元素指向的柱子的高度,则把当前柱子的下标push进栈(保证栈中的柱子高度是递增的)。
② 否则,说明当前柱子高度低于栈顶元素指向的柱子的高度,则将栈顶pop出,并判断新栈顶柱子(不包括)到当前柱子(不包括)的长度×pop出的原栈顶的柱子的高度是否大于ans,是则就刷新ans。(这里为什么是新栈顶柱子而不是原栈顶柱子呢?因为在栈里的元素都是经过筛选递增的,连个元素之间是一个“山峰”,但由于被原栈顶元素限制,因此两个元素之间的“山峰”只能看成高度和右边柱子的高度一样,则从新栈顶+1的柱子到原栈顶柱子的高度都被看成一样是原栈顶柱子的高度)
最后遍历一遍栈,判断从最后一个柱子到新栈顶柱子(不包括)的长度×原栈顶柱子高度是否大于ans,是则刷新ans。
对于步骤②可能看得不太清楚,这里考虑一下上图的例子:
当前柱子下标为4,则根据步骤①可以知道,栈中的元素为1、2、3。
此时发现,当前柱子[4]高度小于栈顶柱子[3]高度,则执行步骤②,将栈顶[3]pop出来,新栈顶变为[2],此时计算矩形面积为6*1=6,则ans更新为6;再判断,发现栈顶柱子[2]高度依然高于当前柱子[4]高度,则将栈顶[2]pop出来,新栈顶变为[1],此时再计算矩形面积为5*2=10,ans更新为10;最后将[4]push进栈,栈中元素变为1、4。以此类推。
三 代码
python版:
class Solution:
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
stack = []
index = 0
ans = 0
size = len(heights)
while index < size:
if len(stack) == 0 or heights[index] >= heights[stack[-1]]:
stack.append(index)
index = index + 1
else:
up = heights[stack[-1]]
stack.pop()
if len(stack) == 0:
ans = max(ans, up * index)
else:
ans = max(ans, up * (index - stack[-1] - 1))
while len(stack) != 0:
up = heights[stack[-1]]
stack.pop()
if len(stack) == 0:
ans = max(ans, up * index)
else:
ans = max(ans, up * (index - stack[-1] - 1))
return ans
C++版:
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int largestRectangleArea(vector<int>& heights) {
stack<int> stk;
int index = 0, ans = 0, size = heights.size();
while(index < size) {
if(stk.empty() || heights[index] >= heights[stk.top()]) { //栈为空或者第i个柱体高于栈顶柱体
stk.push(index++);
}
else { //第i个柱体比栈顶柱体矮
int up = heights[stk.top()];
stk.pop();
int width = stk.empty() ? index : index - stk.top() - 1;
ans = max(ans, up * width); //新栈顶指示的下标以后的柱体高度和up相同
}
}
while(!stk.empty()) {
int up = heights[stk.top()];
stk.pop();
int width = stk.empty() ? index : index - stk.top() - 1;
ans = max(ans, up * width);
}
return ans;
}