之前做到LeetCode题目接雨水的时候就看到单调栈,但是当时觉得动态规划更好理解,所以就没有深入了解。之后做到矩形问题的时候,觉得应该做个笔记来加深下理解。
柱状图中最大的矩形
首先贴上代码块
public class Solution(){
public int largestRectangleArea(int[] heights){
int n = heights.length;
if (n == 0){
return 0;
}
if (n == 1){
return heights[0];
}
int ans = 0;
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < n; i++){
//需要注意弹栈的时候栈为空
//栈顶元素大于当前元素,栈中元素才被弹出,如果后面元素一直增大,则一直加入栈中
while (!stack.isEmpty() && heights[stack.peekLast()] > heights[i]){
int height = heights[stack.removeLast()];//此时栈顶元素被弹出
//判断之前有没有相等的元素
while (!stack.isEmpty() && heights[stack.peekLast()] == height){
stack.removeLast();
}
int width;
if (stack.isEmpty()){
width = i;
}
else{
width = i - stack.peekLast() - 1;
}
ans = Math.max(ans, width * height);
}
stack.addLast(i);
}
//遍历完成后,栈中还有元素
while (!stack.isEmpty()){
int height = heights[stack.removeLast()];
while (!stack.isEmpty() && heights[stack.peekLast()] == height){
stack.removeLast();
}
int width;
if (stack.isEmpty()){
width = n;
}
else{
width = n - stack.peekLast() - 1;
}
ans = Math.max(ans, width * height);
}
return ans;
}
}
栈的思想是后进先出,跟addFirst还是addLast没什么关系。如果你入栈addFirst,出栈就应该removeFirst,反之入栈addLast,出栈就应该removeLast。对于数组而言,想要作为栈,数组的实现比较自然的想法是在末尾进行进行操作。
加了哨兵之后的代码
public class Solution {
public int largestRectangleArea(int[] heights) {
int n = heights.length;
if (n == 0) {
return 0;
}
if (n == 1) {
return heights[0];
}
int ans = 0;
int[] newHeights = new int[n+2];
newHeights[0] = 0;
System.arraycopy(heights, 0, newHeights,1,n);
newHeights[n+1] = 0;
n += 2;
heights = newHeights;
Deque<Integer> stack = new ArrayDeque<>(n);
stack.addLast(0);
for (int i = 0; i < n; i++) {
while (heights[stack.peekLast()] > heights[i]) {
int curheight = heights[stack.removeLast()];
int curWidth = i - stack.peekLast() - 1;
ans = Math.max(ans, curWidth * curheight);
}
stack.addLast(i);
}
return ans;
}
}