栈
使用场景
利用其先进后出属性,可用于成对匹配等等。
例题
单调栈
顾名思义,单调递增栈中的数值从栈顶到栈底是从小到大,先入栈的值大于等于后入的值;单调递减栈反之。
使用场景
- 适用于无规律的排队后,需要遍历两遍及以上来统计数值的场景
- 适用于寻找满足一定位置关系同时满足其他条件的值,比如,找到自己之前最近的比自己小的值等等
难点
这类题目的难点是发现可用单调栈解法和定义入栈的数值的意义。
例题
1. 求最大矩形面积
给出一个矩形统计图,它的每个矩形的宽度都为1,高度如图。求出这个矩形图中最大面积的长方形。
思路
一列一列看,如果当前列的高度小于等于前面列的高度,那么当前列可以融入前面的列,与之构成一个矩形,形成的矩形高度被当前列的高度限制,此时,记录下当前列的索引和高度同时需要清除前面的索引及高度的记录;反之,如果当前列的高度大于前面列,那么该列无法与前面的列构成矩形,只能存储当前列的高度和索引,以供后续计算。由此此题存储数据的特性,可以构建一个非传统的单调递减栈(比较高度,存入索引)注意只有在出栈时才计算面积。
实现步骤
-
首先往栈中投入一个高度为0,索引为-1的值,作为第一列前面的空值
-
开始取数,索引为0的列高度为1,比栈顶数据(0)大,将该列数据入栈
-
索引为1的列高度为4,比栈顶数据(1)大,将该列数据入栈
-
索引为2的列高度为3,比栈顶数据(4)小,栈顶出栈,计算其矩形大小为4×(1-0)=4,更新最大面积;当前栈顶数据(1)小于当前列数据,将该列数据入栈;
-
索引为3的列高度为2,比栈顶数据(3)小,栈顶出栈,计算其矩形大小为3×(2-0)=6,更新最大面积;当前栈顶数据(1)小于当前列数据,将该列数据入栈;
-
索引为4的列高度为2,与栈顶数据一致,更新栈顶数据索引为当前列索引;
-
索引为5的列高度为5,比栈顶数据大,将该列数据入栈;
-
索引为6的列高度为6,比栈顶数据大,将该列数据入栈;
-
后面没有数据了,全部出栈:
- 栈顶出栈,计算其矩形大小为6×(6-5)=6,更新最大面积,保留其索引6;
- 栈顶出栈,计算其矩形大小为5×(6-4)=10,更新最大面积;
- 栈顶出栈,计算其矩形大小为2×(6-0)=12,更新最大面积;
- 栈顶出栈,计算其矩形大小为1×(6-(-1))=7,更新最大面积;
-
得到最大面积的值
代码实现
public int maxArea(int[] heights) {
Stack<Integer> stack = new Stack<>();
int maxArea = 0;
/* 初始准备 */
stack.push(-1);
stack.push(0);
for (int i = 1; i < heights.length; ) {
/* 一一比较高度,做计算 */
if (stack.peek() == -1 || heights[i] > heights[stack.peek()]) {
stack.push(i);
i++;
} else if (heights[i] == heights[stack.peek()]) {
stack.pop();
stack.push(i);
i++;
} else {
maxArea = Math.max(maxArea, heights[i - 1] * (stack.pop() - stack.peek()));
}
}
/* 遍历栈中剩余数值 */
int right = heights[stack.peek()];
while (stack.peek() != -1) {
maxArea = Math.max(maxArea, heights[stack.pop()] * (right - stack.peek()));
}
return maxArea;
}
2. 求最大矩形面积升阶版
给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
例如:
1 1 1 0
其中,最大的矩形区域有3个1,所以返回3。
再如:
1 0 1 1
1 1 1 1
1 1 1 0
其中,最大的矩形区域有6个1,所以返回6。
思路
一行一行看,就是上一道题。每一行的高度等于当前高度加上上面所有行的高度;注意遇0清零,前面行的高度就不会被计算入之后的高度中。
代码实现
public int maxArea1(int[][] map) {
int max = 0;
int[] heights = new int[map[0].length];
for (int[] row : map) {
for (int i = 0; i < row.length; i++) {
if (row[i] != 0) {
heights[i] += row[i];
} else {
heights[i] = 0;
}
}
max = Math.max(max, maxArea(heights));
}
return max;
}
引用