系列文章目录
前言
每天进步一点点!!
一、背景
来源:力扣
链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
二、我的思路
我的思路是错误的,但还是写一下。
总体就是一次遍历,计算当前最小的高*长度(元素个数)是否比当前数组元素(其长度为1,高为数组值)的面积大,如果大,说明可以累加这个元素,如果不大,说明这个时候需要更换最小的高为当前元素的值了。
如此荒唐的思维,都没有验证可行性,我就下手敲出来了,结果遇到【1,2,3,4,5】这个数组的时候,给我整蒙了。
附上没有AC的代码,毕竟是我自己想的,只通过了72个用例,总共九十多个。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int > my_stack;
int maxArea=0;
int minHeight=INT_MAX;
for (int i=0,j=0;i<heights.size();i++,j++)
{
minHeight=min(minHeight,heights[i]);
int area=max(minHeight*(j+1),heights[i]);
maxArea=max(maxArea,area);
if(minHeight*(j+1)<=heights[i])
{
minHeight=heights[i];
j=0;
}
// my_stack.push(maxArea);
}
return maxArea;
}
};
三、官方的思路
1.单调栈
依据官方的思路,我自己写了代码。
总体思想是,遍历数组的时候,找到当前元素的左边届,同理找到右边界。
这个边界是什么意思呢,表示如果用当前这个元素做高,那么它的长度可以是多少,最后计算面积就是:当前元素值*连续的数组元素长。
举例:如何找到元素值为4的左边界,你就看呀,该元素左侧是不是都>=4,直到符合的那一项,记录它的下标,这个就是他的左边界。办法就是用栈取存元素。判断当前元素是否比栈里面的元素小,小的话,就不停出栈。(为什么是小,因为我栈底元素放的是下标-1,表示最左边。如果当前元素一直小于它左侧的元素,那么它的左边界不就接近最左侧嘛,所以这个时候需要出栈)。右侧同理,不过它的栈底元素可以压入数组长度。
代码如下:
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int > s;//用栈实现记录
vector<int > left;//记录左边界
vector<int > right(heights.size());//记录右边界
int maxArea=0;//记录最大面积
s.push(-1);
for (int i=0;i<heights.size();i++)
{
while (s.top()>=0&&heights[i]<=heights[s.top()])
{
s.pop();
}
left.push_back(s.top());//记录左侧边界
s.push(i);//把当前元素下标压入栈
}
//把栈清空
while (!s.empty()){
s.pop();
}
s.push(heights.size());
for (int i=heights.size()-1;i>=0;i--)
{
while (s.top()<heights.size()&&heights[i]<=heights[s.top()])
{
s.pop();
}
right[i]=s.top();//记录右侧边界
s.push(i);//把当前元素下标压入栈
}
//求得面积
for (int i=0;i<heights.size();i++)
{
maxArea=max(maxArea,heights[i]*(right[i]-left[i]-1));
}
return maxArea;
}
};
2.单调栈优化
前面的是左右边界分开求,这里一起求,办法就是,每次出栈的话,说明当前栈顶对应元素的右边界为当前的元素,想一下,如果不是这样,那么为什么要出栈呢?
代码如下;
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int > s;//用栈实现记录
vector<int > left;//记录左边界
vector<int > right(heights.size(),heights.size());//记录右边界
int maxArea=0;//记录最大面积
s.push(-1);
for (int i=0;i<heights.size();i++)
{
while (s.top()>=0&&heights[i]<=heights[s.top()])
{
right[s.top()]=i;//记录右侧边界
s.pop();
}
left.push_back(s.top());//记录左侧边界
s.push(i);//把当前元素下标压入栈
}
//求得面积
for (int i=0;i<heights.size();i++)
{
maxArea=max(maxArea,heights[i]*(right[i]-left[i]-1));
}
return maxArea;
}
};
细节:
1、初始化右边界所有的数组值为数组长度,那是因为最后留在栈里面的,其右边界都是最右边。
2、清空栈的办法可以用:s=stack();而不是用while不停pop
总结
有些题目,它本身就是套路,如果没有好的办法,那么直接看人家是怎么写把,毕竟,我们不是创造这个办法的人,我们只是想要一份不错的工作。
创新就交给那些更具天赋的人吧!!!