1. 柱状图中的最大矩阵
- 这道题和接雨水有点像,但是接雨水是求两边的最大值来计算,本题是寻找两边最小的值来计算
- 栈顶到栈底的排列顺序是从大到小的顺序
单调栈解法
class Solution {
public:
// 寻找的是左右两边第一个小于 top 的值, 因此单调栈内 栈顶到栈底是从大大小排列的
int largestRectangleArea(vector<int>& heights) {
int result = 0;
stack<int> st;
// 数组头部和尾部加入 元素0
heights.insert(heights.begin(), 0);
heights.insert(heights.end(), 0);
st.push(0);
for(int i=1; i<heights.size(); i++){
if(heights[i] > heights[st.top()]){
st.push(i);
}else if(heights[i] == heights[st.top()]){
st.pop();
st.push(i);
}else{
while(!st.empty() && heights[i] < heights[st.top()]){
int mid = st.top();
st.pop();
if(!st.empty()){
int left = st.top();
int right = i;
int w = right - left - 1;
int h = heights[mid];
result = max(result, w*h);
}
}
st.push(i);
}
}
return result;
}
};
双指针解法
class Solution {
public:
// 2.双指针解法
int largestRectangleArea(vector<int>& heights) {
int len = heights.size();
// 1.使用数组存储每个元素对应的两边 第一个比当前元素小的下标
vector<int> minLeft(len, 0);
vector<int> minRight(len, 0);
// 因为左右边界 都分别没有左边和右边第一个小的值,因此初始化的时候可以初始化为其他数
minLeft[0] = -1; // 防止下面的while死循环
minRight[len-1] = len; // 防止while死循环
for(int i=1; i<len; i++){
int t = i-1; // 这里使用t为了寻找左边第一个小的值
while(t >=0 && heights[t] >= heights[i]) t = minLeft[t];
minLeft[i] = t;
}
for(int i=len-2; i>=0; i--){
int t = i+1;
while(t<len && heights[t]>=heights[i]) t = minRight[t];
minRight[i] = t;
}
// 求和
int result = 0;
for(int i=0; i<len; i++){
int sum = heights[i] * (minRight[i] - minLeft[i] - 1);
result = max(result, sum);
}
return result;
}
};