今天是国庆假期后的恢复做题的第一天,摆了那么久感觉还是有点没摆够哈哈哈哈!今天两道题都是困难题,两道题都去看讲解了,感觉这两道题是高度相似的,接雨水用单调递增栈来做,柱状图中最大的矩形用单调递减栈来做。
42. 接雨水
这道题还是延续之前的思路,用单调递增栈来做,即从栈顶到栈底为单调递增。雨水的体积就是这些柱子能够围成的凹槽的面积,遍历所有柱子,当遍历到的柱子高度小于等于栈顶的高度时,就将当前遍历到的柱子也压入栈中,这样符合单调递减栈的设计;当遍历到的柱子高度大于栈顶柱子的高度时,这就需要取出栈中的元素来计算结果了,先将栈顶元素用一个变量mid保存,再将栈顶元素弹出,该变量作为凹槽中的最底部,当前遍历的柱子作为凹槽中的右侧墙壁,弹出元素后新的栈顶元素作为凹槽中的左侧墙壁,如图所示。
当然这个计算过程是一个持续的过程,并不是计算一次就接着遍历下一根柱子了,考虑这么一种情况:输入数组为[8, 7, 6, 8],当遍历到最后一个8时触发计算条件,进入while循环,倘若没有while循环的话,计算一次结果后就会因为遍历完最后一根柱子而退出外层for循环,导致雨水量少算了。正确计算雨水的过程如图所示。
还有一个情况要考虑,就是在触发计算条件时,当把栈顶元素用mid保存后弹出时,需要立即判断栈是否为空,如果栈已经为空了,就说明下一步无法计算了,强行计算会报错,所以栈为空的话就直接将当前遍历到的柱子压入栈中即可。具体例子看下面这张图。
这种情况下是接不了雨水的,所以需要额外对栈是否为空进行判定。
这是代码
class Solution {
public:
int trap(vector<int>& height) {
int result = 0;
stack<int> st; //从栈顶到栈底是单调递增的
st.push(0);
for(int i = 1; i < height.size(); i++){
if(height[i] <= height[st.top()]) //当前遍历元素小于等于栈顶元素,直接压入栈中
st.push(i);
else{ //当前遍历元素大于栈顶元素,开始计算雨水量
while(!st.empty() && height[i] > height[st.top()]){
int mid = st.top();
st.pop();
if(!st.empty()){ //栈不为空才进行下一步计算雨水操作,否则会越界访问报错
int w = i - st.top() - 1;
int h = min(height[i], height[st.top()]) - height[mid];
result += w * h;
}
}
st.push(i);
}
}
return result;
}
};
84.柱状图中最大的矩形
这道题的代码整体结构和上一题很像,这一题主要是用单调递减栈来做的,即栈顶到栈底单调递减,此外这里还有个小细节,就是这道题需要在原数组的首部和尾部插入0,具体后面会讲。
首先还是介绍一下触发计算条件时的一般计算过程,如下图所示。
计算矩形面积的时候,是以heights[mid]为高度,当前遍历到的柱子与新的栈顶中的柱子之间的间隔为宽的矩形来计算的。下面也再模拟一次持续计算的过程。考虑输入为[1, 2, 3, 2, 1],当遍历到第二个2时触发计算条件。如下图所示。
三个2拼接成面积为6的情况将在下一次外循环,即遍历到最后一个1时触发计算条件,这里不再赘述。
这里再解释下为什么要在数组的头部和尾部添0,这是因为输入的柱子都遍历完的情况下,还可能存在没有计算的情况,在上面那个例子中,当遍历到最后一个1时,触发计算条件,计算完下面的面积后,循环就终止了,但是高为1的情况被遗漏了。
尽管这种情况计算出来的面积不一定更大,但是这样的情况必须要考虑进去,所以需要在数组的首尾添0,用来触发这种情况的计算。其余的地方都和上一题没啥区别,无非是大于号与小于号互相颠倒。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//先将输入的数组首尾都添0
heights.insert(heights.begin(), 0);
heights.push_back(0);
stack<int> st; //从栈顶到栈底单调递减
st.push(0);
int result = 0;
for(int i= 1; i < heights.size(); i++){
if(heights[i] >= heights[st.top()]) //遍历到的元素大于等于当前栈顶元素,压入栈中
st.push(i);
else{ //遍历到的元素小于当前栈顶元素,开始计算矩形面积
while(!st.empty() && heights[i] < heights[st.top()]){
int mid = st.top();
st.pop();
if(!st.empty()){
int w = i - st.top() - 1;
int h = heights[mid];
result = max(w * h, result);
}
}
st.push(i);
}
}
return result;
}
};
今天是单调栈最后一天了,也是代码随想录视频系列的最后一节了,之后的题目就没有视频讲解了,感觉有点害怕😰