单调栈的定义
- 单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
- 单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大
42、接雨水
解析:
对于每一个高度的柱子来说如果想要以它为底盛水,那么它的左右两根柱子都必须比他要高,所以定义一个单调增栈,先保证栈中的元素左边都比右边要大,这时候只要再添加的元素大于栈顶的元素就满足了接水的条件了,这时候就可以计算以栈顶元素高度为底的能接多少水,算出后将其弹出,再次比较栈顶元素是否还能为底来接水,可以的话继续计算,知道无法再节水为止。左边界条件就是栈里必须有一个元素才可以接水,所以当栈为空时也跳出循环。
class Solution {
public int trap(int[] height) {
int n = height.length;
if(n == 0) return 0;
int res = 0;
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < n; i++){
while(!stack.isEmpty() && height[i] > height[stack.peek()]){
int cur = height[stack.pop()];
if(stack.isEmpty()) break;
int width = i - stack.peek() - 1;
int h = Math.min(height[i], height[stack.peek()]);
res += width * (h - cur);
}
stack.push(i);
}
return res;
}
}
84、柱状图中的最大矩形
解析:确定以一根柱子的高度为高的矩形的体积,宽度要想两边搜索知道遇见高度小于当前高度的矩形停止,即要确定矩形的大小那么他两边的柱子的高度要小于它自己的高度,因此设计一个栈,这个占中的元素栈顶的一定要大于栈底的元素,此时一旦遇见小的元素,就可以计算这个矩形为高的矩形的宽度了,就可以计算出这一块的面积。
以此比较就可以得出最大的面积。
class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
if(n == 0) return 0;
int res = 0;
int[] newheights = new int[n + 2];
newheights[0] = newheights[n + 1] = 0;
for(int i = 1; i < n + 1; i++){
newheights[i] = heights[i - 1];
}
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < n + 2; i++){
while(!stack.isEmpty() && newheights[i] < newheights[stack.peek()]){
int cur = stack.pop();
int curheights = newheights[cur];
int leftIndex = stack.peek();
int rightIndex = i;
int curWidth = rightIndex - leftIndex - 1;
res = Math.max(res, curWidth * curheights);
}
stack.push(i);
}
return res;
}
}
总结:上边两道题目都是分别计算以每一个矩形的高度为底或者为顶,能接的水或者围成的面积,需要确定的就是宽度,根据具体的条件来判断是使用单调增还是单调减栈,这样就可以判断宽度了。
739、每日温度
解析:如果采用暴力算法,对于每一天都向后遍历找高温的话复杂度是n^2,所以想到使用单调栈来解决这样只要遍历一遍数组就可以得出结果复杂度只是n。找高温,那么就使用单调增栈。一旦遇到比当前元素打的就弹出栈计算天数,最后留在栈内的元素就是没有比他高的温度了,直接就是0.
class Solution {
public int[] dailyTemperatures(int[] T) {
int n = T.length;
if(n == 0) return new int[]{};
Stack<Integer> stack = new Stack<>();
int[] res = new int[n];
for(int i = 0; i < n; i++){
while(!stack.isEmpty() && T[i] > T[stack.peek()]){
int cur = stack.pop();
res[cur] = i - cur;
}
stack.push(i);
}
return res;
}
}