题目描述
给定一个可能含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。位置信息包括:两个数字 L 和 R,如果不存在,则值为 -1,下标从 0 开始。
示例1
输入 [3,4,1,5,6,2,7]
返回值 [[-1,2],[0,2],[-1,-1],[2,5],[3,5],[2,-1],[5,-1]]
单调栈的应用很局限,只有这种应用,要不是找左边/右边离自己最近的最小的值,要不就是左边/右边找离自己最大的值,右边亦然。左边的话遍历顺序从前到后,右边的话遍历顺序从后向前。
为什么应用单调栈呢?给定一个数列[a,b,c,d,e] 找该序列中比自己小的最近的数的位置,比如对于d而言,如果b>c 那么离d最近的元素是c,b不会被选到。可以手动模拟一下样例的执行过程便可以深刻感受到单调栈的用法。
求解左边的数字从0开始循环,求解右边的数字从最后一位开始循环。其中栈保存的是下标,栈用的是数组模拟的不是用的库函数。(用数组模拟的原因:栈的操作入栈出栈,入栈相当于数组指针向后移动,出栈相当于数组指针向前移动,因此模型时需要使用到数组存储到什么位置啦)
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums intvector
* @return intvector<vector<>>
*/
vector<vector<int> > foundMonotoneStack(vector<int>& nums) {
// write code here
int n=nums.size();
vector<vector<int>> res(n,vector<int>(2,0));
int stkL[n],stkH[n];
int tl=0,th=0;
for(int i=0;i<n;i++)
{
while(tl&&nums[stkL[tl]]>=nums[i]) tl--;
if(tl) res[i][0]=stkL[tl];
else res[i][0]=-1;
stkL[++tl]=i;//存储的是下标
}
for(int i=n-1;i>=0;i--)
{
while(th&&nums[stkH[th]]>=nums[i]) th--;
if(th) res[i][1]=stkH[th];
else res[i][1]=-1;
stkH[++th]=i;
}
return res;
}
};
leetcode 739 每日温度
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
寻找右边比它大的元素。使用单调栈,且遍历顺序从后向前遍历。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n=temperatures.size();
stack<int> stk;
vector<int> ans(n);
for(int i=n-1;i>=0;i--)
{
while(stk.size() && temperatures[i]>=temperatures[stk.top()]) stk.pop();
if(stk.size()) ans[i]=stk.top()-i;
stk.push(i);
}
return ans;
}
};
84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4]
输出: 4
提示:
1 <= heights.length <=105
0 <= heights[i] <= 104
与盛水最多的容器不同的一点是,矩形不是中空的,是实心的,如果按照盛水最多的容器那种做法,会使得矩阵出现中空这种现象。
既然是实心的,那么就需要知道当前数字 x 可以延伸的左右边界是多少,进一步就需要知道左右两边分别对于当前 x 最左边/最右边离 x 最小的数字是多少? 那么就需要使用单调栈来做该题目。特殊情况,如果左右两边没有比自己小的数字,那么左边赋值为-1,右边赋值为n,最后求解最大的矩阵时只需要遍历每个数字可以看做高,将每个数字乘以矩阵的宽 (right[i]-left[i]-1) 即可得到。
class Solution {
public:
int largestRectangleArea(vector<int>& height) {
stack<int> stk;
int n=height.size();
vector<int> left(n),right(n);
for(int i=0;i<n;i++)
{
int x=height[i];
while(stk.size() && height[stk.top()]>=x) stk.pop();
if(stk.empty()) left[i]=-1;
else left[i]=stk.top();
stk.push(i);
}
stk=stack<int>();
for(int i=n-1;i>=0;i--)
{
int x=height[i];
while(stk.size()&&height[stk.top()]>=x) stk.pop();
if(stk.empty()) right[i]=n;
else right[i]=stk.top();
stk.push(i);
}
int ans=0;
for(int i=0;i<n;i++)
{
ans=max(ans,height[i]*(right[i]-left[i]-1));
}
return ans;
}
};