42. 接雨水(困难-单调栈)×!
单调递减栈中存的是元素下标,不是下标单调递减,而是下标对应的元素单调递减。
整体思路:首先我们用的是单调递减栈,所以当 当前柱子高度比栈顶要大时,说明一定可以接水。
因为是 1 0 2 的关系
1: 如果栈不空,且当前柱子高度大于栈顶,说明出现了水沟
2: bottomIndex是水沟所在的下标, 然后出栈
3: 如果栈空了,说明没有左边的柱子,或者说当前是单调增的趋势,那么就把栈顶pop,然后break结束while,然后把当前的柱子下标入栈,维持单调递减栈的性质。
4: 由于刚才的bottomIndex已经出栈,所以现在栈顶元素是左柱子元素的下标
5: 水沟的高度就是左右柱子高度的最小值减去水沟的高度
6:这里要强调的是,由于计算了一个水沟之后,会出栈,因此,比如倒着的“土”,当中间的块出栈之后,
会变成“一”块,此时是不符合单调递减栈的,但是下一个柱子入栈时会一起计算这个“一”的面积。
class Solution {
public:
int trap(vector<int>& height) {
int res = 0;
stack<int> stk; // 单调递减栈 (注意存的不是高度是下标!)
for(int cur = 0; cur < height.size(); ++cur){
while(!stk.empty() && height[cur] > height[stk.top()]){ // 1
int bottomIndex = stk.top(); stk.pop(); // 2
if(stk.empty()) break; // 3
int l = stk.top(), r = cur; // 4
int h = min(height[l], height[r]) - height[bottomIndex]; // 5
res = res + (r - l - 1) * h; // 6
}
stk.push(cur);
}
return res;
}
};
84. 柱状图中最大的矩形(困难-单调栈)×!×
对于2 1 2 来说 添加了边界变成 0 2 1 2 0 (下面为了简化说明,指的都是元素对应的元素,而不是下标)
当栈内有 0 2 时, 1 准备入栈,发现不符合单调递增栈的性质;所以对于2 来说,以2为高度的最大矩形就已经确定,就是2;
然后1入栈,2入栈;栈内有0 1 2 ;
0入栈,2为高度的矩形确定;出栈;
此时栈内还有0, 1 ;此时需要确定1为高度的矩形;
int curHeight = heights[st.top()]; st.pop(); // 1的下标出栈,这里能说明为什么必须获得了高度之后紧接着就要出栈,因为这样才能获得以1为高度的左端点的下标(因为现在栈内的0 1,原先它们之间是有个2的,只是以2为高度的矩形已经算完了,所以2出去了,但它比1大,所以可以用它作为左端点)
int left = st.top() + 1; // (因为是单调递增栈,如果0 1 是紧挨着,那么left就是1的下标(st.top() + 1)。如果原来它们之间还有元素,要么比1大,但是肯定已经出栈了,st.top() + 1 就是第一个大于1的元素的下标)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
heights.insert(heights.begin(), 0);
heights.push_back(0);
int res = 0;
stack<int> stk;
for(int i = 0; i < heights.size(); ++i){
while(!stk.empty() && heights[i] < heights[stk.top()]){
int height = heights[stk.top()]; stk.pop();
int left = stk.top() + 1;
res = max(res, (i - left) * height);
}
stk.push(i);
}
return res;
}
};
85. 最大矩形(困难-单调栈)×
/*
跟84解法一样,只是要将84的解法用m - 1次求出最大值。主要还是要夯实84题。
就是以每一行为x轴算出一个柱状图的vector<int>, 然后算出最大面积就可以了。
1:这里要注意,虽然从图里看最高的一层在顶上,但是从矩阵看它就是第一行,所以i,j都从0遍历。
2:如果当前是1,那么可以加上之前的高度,只要是0,那么就是0。
3:这里要注意不能用引用,因为解法中要对heights增加左右边界,所以要传值,不能改变heights的大小。
*/
class Solution {
public:
int maximalRectangle(vector<vector<char>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
int res = 0;
vector<int> heights(n);
for(int i = 0; i < m; ++i){ // 1
for(int j = 0; j < n; ++j){
if(matrix[i][j] == '1') heights[j] += matrix[i][j] - '0'; // 2
else heights[j] = 0;
}
res = max(res, largestRectangleArea(heights));
}
return res;
}
int largestRectangleArea(vector<int> heights) { // 3
heights.insert(heights.begin(), 0);
heights.push_back(0);
int res = 0;
stack<int> stk;
for(int i = 0; i < heights.size(); ++i){
while(!stk.empty() && heights[i] < heights[stk.top()]){
int height = heights[stk.top()]; stk.pop();
int left = stk.top() + 1;
res = max(res, (i - left) * height);
}
stk.push(i);
}
return res;
}
};
739. 每日温度(中等-单调栈)√
说来搞笑,这个题一开始我是只能想到暴力解的,然后我去看题解,先看到一个栈字,我在想跟栈有什么关系?又看到单调栈,然后一瞬间就会做了。
主要是脑子里没建立起一个哈希映射,到底什么样的题能用到单调栈?
现在我还想不到答案,按我自己做过几道单调栈的题目的经验来说,一般题目是一维数组,需要用O(n2)的暴力解来做,都可以试试单调栈(不一定能用上,但是要往这想想)。
思路:
用个单调递减栈,假设temperatures为[3,2,1,4];
- 3,2,1符合单调递减,肯定依次入栈,当i为3时,发现4大于栈顶,那么对于1来说,它的下一个最高温度就是第i = 3天,1出栈;
- 此时栈顶为1,4仍然大于2;因为是单调递减的,2和4之间要么原来没有元素,要么有元素也肯定比2小。所以2的下一个最大温度就是3 - 1 = 2天后。
- 最后栈内剩下的元素都是递减的,并且没有比他们高的温度的日期,又因为res的所有元素默认初始化为0,所以不用处理,直接返回。
- 需要强调的是栈内存储的是元素的下标!不是元素!切记!
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n = temperatures.size();
stack<int> stk;
vector<int> res(n);
for(int i = 0; i < n; ++i){
while(!stk.empty() && temperatures[i] > temperatures[stk.top()]){
int d = stk.top(); stk.pop();
res[d] = i - d;
}
stk.push(i);
}
return res;
}
};