题目大意
这题也是hdu 1506.
给定一个数组heights,其中heights[i]代表一个底为1,高为heights[i]的矩形。现在问你这个数组的所形成的“直方图”中最大的矩形面积。
思路
首先介绍一下单调队列与单调栈。顾名思义,就是容器内元素是单调的。重点就是在将元素压入容器的时候需要保持容器内的有序性。
对于单调栈来说,一个很简单的应用是:求某一个元素左边(右边)比它大(小)的第一个元素。思路就是如果i < j && arr[i] > arr[j]
那么对于j之后的元素来说,i就已经失去了意义(相当于把i从堆栈弹出去)。
对于单调队列来说,一个很简单的应用是求滑动窗口区间内的最值。因为窗口每滑动一次,只有一个数进入窗口,一个数离开窗口,因此可以用单调队列来维护。实现可以用stl的双端队列deque。
现在来看这道题,隐约觉得这道题既和数的大小有关,又和数的位置有关,因此觉得可以用单调栈来做。思考一下,如果从左往右考虑,有两个数arr[i]与arr[j],如果i < j 且 ar[i] > arr[j],那么对于j以后的数来说,arr[i]就失去了意义。此时就可以将arr[i]出栈。因此我要维护一个单调递增栈。那么面积怎么算呢?由于单调递增性质,假设当前位置为j,而栈顶元素为位置i,那么i到j-1之间的矩形高度一定都是大于j位置的高度的。如果不明白可以看代码,自己在纸上画一画就可以理解了。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int res = 0, area = 0;
stack<int> st;
heights.push_back(0); //末尾添加一个0保证全部元素都出栈计算面积
for (int i = 0; i < heights.size(); i++) {
while (!st.empty() && heights[st.top()] >= heights[i]) {
int cur = st.top(); st.pop();
area = heights[cur] * (st.empty() ? i : i-1-st.top()); //好好想一下这个底的计算
res = max(res, area);
}
st.push(i);
}
return res;
}
};
Maximal Rectangle
Also Poj 3494
上一道题的延伸。这个最大的矩形怎么求呢?这样考虑:对于每一行来说,我把这一行每一列开始连续的1的个数看为高度,那么实际就是求Largest Rectangle in Histogram。我处理好数据之后对每一行都做一次,就得到了最终的Maximal Rectangle.
class Solution {
public:
int sol(vector<int> heights) {
int ans = 0;
stack<int> st;
for (int i = 0; i < heights.size(); i++) {
while (!st.empty() && heights[st.top()] > heights[i]) {
int cur = st.top(); st.pop();
ans = max(ans, heights[cur] * (st.empty() ? i : i-st.top()-1));
}
st.push(i);
}
return ans;
}
int maximalRectangle(vector<vector<char>>& matrix) {
if (matrix.size() == 0 || matrix[0].size() == 0) return 0;
int m = matrix.size(), n = matrix[0].size(), res = 0;
vector<int> heights(n+1, 0);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '0') {
heights[j] = 0;
} else
heights[j] = i == 0 ? 1 : heights[j]+1;
}
//先做好数据转换的工作。
res = max(res, sol(heights));
}
return res;
}
};
结语
两道感觉很不错的题目,一年前做过现在再来看早已经想不起来思路了,现在重新整理一遍思路。