单调栈即栈内元素必须单调增或者单调减,假设有数组arr[2,1,5,6,2,3],求数组中每个数字左右两边离他最近的比他小的数,
2: 左边—无 右边—1
1: 左边—无 右边—无
5: 左边—1 右边—2
。。。
最容易想到的方法是对于每个数字,分别从左遍历到此位置找到左边最近且最小的数字,从右遍历到此位置找到右边最近且最小的数字,对于每一个数时间复杂度O(n),数组大小为n,每个数都计算几次时间复杂度O(n^2),单调栈可以将问题的复杂度降为O(n):
建立一个单调栈s,栈中元素从下到上一次递增,将数组元素入栈,若入栈时发现不能满足单调栈的性质则先出栈,直到入栈元素可以满足单调栈的性质为止,每次出栈时记录出栈元素下方的数字和迫使他出栈的数字即为出栈数组左右两边最近的比他小的数。
对于上面的数组,2先入栈,当1再入栈时,发现不能满足从下向上递增的规律,则2出栈,此时2下方没有数字,则2左边没有比他小的数,1迫使2出栈,所以1是2右边离他最近比他小的数,2出栈后1入栈,此时栈中元素为1,然后5,6入栈,都满足单调栈的性质,当下一个2入栈时,6先出栈,则6左边离他最近比他小的数字为他下方的数字5,2迫使6出栈,6右边离他最近比他小的数字是2,6出栈后2还不能入栈,5继续出栈,那么5左边离他最近比他小的数字是2,右边离他最近比他小的数是是他出栈的2,依次类推。
LeetCode 84. Largest Rectangle in Histogram 这题目是给定直方图,求直方图中最大的矩形面积
题目:https://leetcode.com/problems/largest-rectangle-in-histogram/description/
此题就可以使用单调栈的应用,直方图的每一项若两边的数字大于他,则可以向两边延伸,每一项都可以延伸到两边离他最近比他小的那一项停止,那么此题就转化为求每一项两边离他最近比他小的位置,计算构成的最大面积,因为要用到位置,所以单调栈中存放索引,在比较时用索引的值:
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int> s;
int res = 0,len = heights.size();
for(int i=0;i<heights.size();i++){
if(s.empty()||heights[i]>heights[s.top()]){
s.push(i);
}
else if(!s.empty()){
while(!s.empty()&&heights[i]<=heights[s.top()]){
int temp = s.top();
s.pop();
if(!s.empty())
res = max(res,heights[temp]*(i-s.top()-1));
else res = max(res,heights[temp]*(i));
}
s.push(i);
}
}
while(!s.empty()){
int temp = s.top();
s.pop();
if(!s.empty())
res = max(res,heights[temp]*(len-s.top()-1));
else res = max(res,heights[temp]*len);
}
return res;
}
};