单调栈的使用场景:通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。
在使用单调栈的时候首先要明确如下几点:
1.单调栈中只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。
2.单调栈中的元素是递增还是递减:
(1)如果是求栈顶元素在数组中右边第一个比栈顶元素大的元素,则栈中栈底到栈顶的元素大小的递减的——新元素比栈顶元素大,则获取比栈顶元素更大的第一个元素,弹出原有栈顶元素;当新元素比栈顶元素小或栈内为空,则将新元素的下标压入栈中;
(2)如果是求栈顶元素在数组中右边第一个比栈顶元素小的元素,则栈中栈底到栈顶的元素大小的递增的——新元素比栈顶元素小,则获取比栈顶元素更小的第一个元素,弹出原有栈顶元素;当新元素比栈顶元素大或栈内为空,则将新元素的下标压入栈中;
1.每日温度
//求右边第一个更大的元素,维护一个单调栈,使得栈内从栈底--->栈顶,呈现大---->小的顺序
//求右边第一个更小的元素,维护一个单调栈,使得栈内从栈底--->栈顶,呈现小---->大的顺序
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> sta;
//将数组的索引压入栈中,根据索引可以直接获得数组元素
sta.push(0);
//用于存放每个元素右边与第一个更大数的距离
vector<int> array(temperatures.size());
for(int i=1;i<temperatures.size();i++)
{
//当前遍历的数>栈顶元素时,说明该元素是栈顶元素右边第一个更大的数,弹出栈顶元素,保存栈顶元素与当前遍历元素的索引差。
while(!sta.empty()&&temperatures[i]>temperatures[sta.top()])
{
array[sta.top()]=i-sta.top();
sta.pop();
}
//如果当前遍历的元素小于栈顶元素时或者栈内为空时,将当前遍历的元素索引压入栈内。
sta.push(i);
}
return array;
}
};
2.下一个更大元素|
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
//第一步,先获得nums2数组中每个元素的右边第一个更大的元素存入数组array中
stack<int> sta;
sta.push(0);
vector<int> array(nums2.size(),-1);
for(int i=1;i<nums2.size();i++)
{
while(!sta.empty()&&nums2[i]>nums2[sta.top()])
{
array[sta.top()]=nums2[i];
sta.pop();
}
sta.push(i);
}
//第二步:寻找与nums1元素相同的nums2数组中的元素,将其对应的array数组中的元素存入结果数组中
vector<int> result(nums1.size());
for(int i=0;i<nums1.size();i++)
{
for(int j=0;j<nums2.size();j++)
{
if(nums1[i]==nums2[j])
{
result[i]=array[j];
break;
}
}
}
return result;
}
};
3.下一个更大元素||
//由于遍历的是一个循环数组,所以遍历的时候将两个原来的数组拼接成一个数组,然后按照常规寻找右边下一个更大的元素即可
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
vector<int> array(nums.size(),-1);
stack<int> sta;
for(int i=0;i<2;i++)
{
for(int j=0;j<nums.size();j++)
{
if(sta.empty())
{
sta.push(j);
continue;
}
while(!sta.empty()&&nums[j]>nums[sta.top()])
{
array[sta.top()]=nums[j];
sta.pop();
}
sta.push(j);
}
}
return array;
}
};
4.接雨水
做题关键:寻找每根柱子height[i]左边最高的柱子height_L[i],右边最高的柱子height_R[i],每根柱子可以接的雨水总量为min(height_L[i],height_R[i])-height[i],统计所有柱子可以接的水量之和。
class Solution {
public:
int trap(vector<int>& height) {
//获得每根柱子左边大于该柱子的最高柱子
vector<int> height_L(height.size());
int ML=0;
for(int i=0;i<height.size();i++)
{
if(ML>=height[i])
height_L[i]=ML;
ML=max(ML,height[i]);
}
//获得每根柱子右边大于该柱子的最高柱子
vector<int> height_R(height.size());
int MR=0;
for(int i=height.size()-1;i>=0;i--)
{
if(MR>=height[i])
height_R[i]=MR;
MR=max(MR,height[i]);
}
//遍历累加每个柱子可以收集的雨水之和
int result=0;
for(int i=0;i<height.size();i++)
{
if(min(height_L[i],height_R[i])-height[i]>0)
result+=(min(height_L[i],height_R[i])-height[i]);
}
return result;
}
};
5.柱状图中最大的矩形
题目要点:对于每根柱子i进行判断,找到柱子i左边第一个比柱子i低的柱子坐标ileft,找到柱子i右边第一个比柱子i低的柱子坐标iright;
对于当前柱子i计算,area[i]=heights[i]*(iright-ileft-1),result=max(area[i]........)
//题目要点!!!!!!!!!!!对于每根柱子i进行判断
//找到柱子i左边第一个比柱子i低的柱子坐标ileft
//找到柱子i右边第一个比柱子i低的柱子坐标iright
//对于当前柱子i计算,area[i]=heights[i]*(iright-ileft-1)
//result=max(area[i]........)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int result=0;
//寻找每个元素左边第一个更小的元素的索引
stack<int> stal;
stal.push(heights.size()-1);
vector<int> heights_L(heights.size(),-1);
for(int i=heights.size()-1;i>=0;i--)
{
while(!stal.empty()&&heights[i]<heights[stal.top()])
{
heights_L[stal.top()]=i;
stal.pop();
}
stal.push(i);
}
//寻找每个元素右边第一个更小的元素的索引
stack<int> star;
star.push(0);
vector<int> heights_R(heights.size(),heights.size());
for(int i=0;i<=heights.size()-1;i++)
{
while(!star.empty()&&heights[i]<heights[star.top()])
{
heights_R[star.top()]=i;
star.pop();
}
star.push(i);
}
//计算以heights[i]为高度的矩形面积,寻找最大值
for(int i=0;i<=heights.size()-1;i++)
{
result=max(result,(heights_R[i]-heights_L[i]-1)*heights[i]);
}
return result;
}
};
参考代码随想录