题目描述:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例:
输入: [2,1,5,6,2,3]
输出: 10
解题思路:
最开始看到这道题以为是dp,然后写了半天递推公式发现是错的。
这道题有两种解法,一种是暴力,一种是单调栈。
暴力
暴力的思想很简单,就是对于每一个位置中心展开就行了,时间复杂度是O(n^2),但是这道题过不了。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//暴力
int ans = 0;
int length = heights.size();
for(int i =0;i<length;i++)
{
int temp=heights[i];
if(i>=1)
{
for(int j=i-1;j>=0;j--)
{
if(heights[j] < heights[i])
break;
else
temp += heights[i];
}
}
if(i<length-1)
{
for(int j=i+1;j<length;j++)
{
if(heights[j] < heights[i])
break;
else
temp += heights[i];
}
}
ans = max(ans,temp);
}
return ans;
}
};
单调栈
一如既往的,看到栈就头晕,不过这次还是把这道题搞出来了。
单调栈的方法是一直往栈中插入比当前栈顶元素大的元素(实际插入的是index,根据index也可以找出元素),因为栈中的元素始终是递增的,所以叫做单调栈。
如果当前元素碰到了比栈顶元素小,那么当前栈顶元素位置的最大面积就可以确定了(因为左右两边都比栈顶的长度小,所以可以确定展开的范围了)
单调栈这种方法好就好在,不用每次都去中心展开遍历,当碰到比栈顶元素小需要确定答案时,右边界一定是当前元素,左边界一定是栈顶的下一个元素。从而就可以直接得出展开范围。
需要注意的点是:
- 注意确定答案时的while循环。也就是说,当碰到比栈顶元素小需要确定答案时,只要栈顶元素比当前元素大,就可以确定答案,所以需要一直pop,直到不能确定答案。
- 注意当栈顶元素和当前元素相等时做的处理,把栈顶pop并加入当前元素。
- 在首尾加入height为0的元素,这样就不用做边界处理了,非常方便。
大致就写这么多,总结一下,当遇到这种需要左右边界来确定答案时,可以用到单调栈。(其实为什么会想到这种方法我也不是很清楚,虽然题做完了,方法理解了,但是对于为什么会选择这种方法本身,还是存在疑惑)class Solution { public: int largestRectangleArea(vector<int>& heights) { stack<int> s; s.push(0); int length = heights.size(); if(length == 0) return 0; int ans = 0; heights.insert(heights.begin(),0); //前面添加一个0 heights.push_back(0); //后面添加一个0 length = heights.size(); for(int i=1;i<length;i++) { int topNum = s.top(); if(heights[i] > heights[topNum]) { s.push(i); } else if(heights[i] == heights[topNum]) { s.pop(); s.push(i); } else { while(heights[s.top()] > heights[i]) { topNum = s.top(); s.pop(); int newTopNum = s.top(); ans = max(ans,(i-newTopNum-1)*heights[topNum]); //cout<<i<<" "<<topNum<<" "<<ans<<endl; } s.push(i); } } return ans; } };
题目链接:
还不懂还可以再去看看官方题解。 https://leetcode-cn.com/problems/largest-rectangle-in-histogram/