一、解题背景
在刷题的过程中遇到部分比较难的题目是需要利用单调栈
的思想来进行求解题目的,这类问题往往有一个统一的思路,需要在遍历的过程中保存一个单调递增的序列或者是单调递减的序列,一旦不满足单调性的时候,就就需要做一些处理来获取我们想要的结果。
二、部分题目
leet84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n = heights.size();
if (n==0) return 0;
int area=0;
// 关键是需要“哨兵”,防止存在一直递增的情况无法结束计算最大矩形
heights.insert(heights.begin(), 0);
heights.push_back(0);
stack<int> st;
st.push(0);
for (int i=1; i<heights.size(); i++) {
while (!st.empty() && heights[i]<heights[st.top()]) {
int h = heights[st.top()];
st.pop();
area = max(area, (i-st.top()-1)*h);
}
st.push(i);
}
return area;
}
};
leet85. 最大矩形
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如下图所示。
class Solution {
public:
// 将这个矩形的从第一层开始,看成多个高度的柱状图,这里可以看做为
/*
每一层看作是柱状图,可以套用84题柱状图的最大面积。
第一层柱状图的高度["1","0","1","0","0"],最大面积为1;
第二层柱状图的高度["2","0","2","1","1"],最大面积为3;
第三层柱状图的高度["3","1","3","2","2"],最大面积为6;
第四层柱状图的高度["4","0","0","3","0"],最大面积为4;
*/
int maximalRectangle(vector<vector<char>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
if (m==0||n==0) return 0;
int ans=0;
vector<int> height(n, 0);
for (int i=0; i<m; i++) {
for (int j=0; j<n; j++) {
if (matrix[i][j]=='1')
height[j]++;
else
height[j]=0;
}
ans = max(ans, largestRecArea(height));
}
return ans;
}
int largestRecArea(vector<int> height) {
height.insert(height.begin(), 0);
height.push_back(0);
stack<int> st;
st.push(0);
int area=0;
for (int i=1; i<height.size(); i++) {
while (!st.empty() && height[st.top()]>height[i]) {
int h= height[st.top()];
st.pop();
area = max(area, (i-st.top()-1)*h);
}
st.push(i);
}
return area;
}
};
leet42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (n==0) return 0;
// 方法一
// int area=0;
// stack<int> st;
// for (int i=0; i<n; i++) {
// while (!st.empty() && height[i]>height[st.top()]) {
// int low = st.top();
// st.pop();
// while (!st.empty() && height[st.top()]==height[low]) {
// st.pop();
// }
// if (!st.empty()) {
// int l = st.top();
// area += (min(height[l], height[i])-height[low])*(i-l-1);
// }
// }
// st.push(i);
// }
// return area;
// 方法二
// 找出对应每个位置左边最大和右边最大的柱子
vector<int> left(n,0);
vector<int> right(n,0);
for (int i=1; i<n; i++) {
left[i] = max(left[i-1], height[i-1]);
}
for (int j=n-2; j>=0; j--) {
right[j] = max(right[j+1], height[j+1]);
}
int area=0;
for (int i=1; i<n-1; i++) {
int level = min(left[i], right[i]);
area += max(0, level-height[i]);
}
return area;
}
};
leet739. 每日温度
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指在第 i 天之后,才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例子:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n = temperatures.size();
if (n==0) return {};
// unordered_map<int,int> mp;
stack<int> st;
vector<int> res(n, 0);
for (int i=0; i<n; i++) {
while (!st.empty() && temperatures[st.top()]<temperatures[i]) {
res[st.top()]=i-st.top();
st.pop();
}
st.push(i);
}
return res;
}
};
leet496. 下一个更大元素 I
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> mp;
vector<int> res;
if (nums1.size()==0) return res;
// 方法一
// for (int i=0; i<nums2.size(); i++) {
// mp[nums2[i]] = i;
// }
// for (auto n:nums1) {
// int idx = mp[n];
// int flag = false;
// for (int j=idx+1; j<nums2.size(); j++) {
// flag = false;
// if (nums2[j]>n) {
// res.push_back(nums2[j]);
// flag = true;
// break;
// }
// else continue;
// }
// if (!flag) res.push_back(-1);
// }
// return res;
// 方法二
res.resize(nums1.size());
stack<int> st;
for (auto n: nums2) {
while (!st.empty() && st.top()<n) {
mp[st.top()]= n;
st.pop();
}
st.push(n);
}
for (int i=0; i<nums1.size(); i++) {
res[i] = mp.find(nums1[i])!=mp.end() ? mp[nums1[i]] : -1;
}
return res;
}
};