单调栈
单调栈是一个比较常用也很好用的一个结构,它的作用是找到某个数的左右边比它大/小的最近的数.
压入栈时,如果即将压入的数值会破坏规则,栈里的数依次弹出,直到栈为空或者不会破坏规则。
弹出数时就能得到结果-->右边最近比它大==因为谁而被弹出
左边最近比它大==栈里它的下面值
面试题:
1.一个数组表示不同矩阵的高度,求矩阵中最大子矩阵的大小。
遍历数组,不断地压入单调栈,就能得出最近比它小的数(当某个数压入单调栈违反了规律),得到最近比它小的数(在单调栈里它的下面),也就能得到我们在求解时需要的——跟它相邻的比它大的数,这里值得注意的是,当栈为空时,左边界赋值为-1,
求出矩阵的面积,不断更新最大值。
只需要遍历一遍这个矩阵就能得到值,因为在单调栈里早已维持好秩序,只要有数被弹出,就可以得到“被弹出的数”离它最近比它小的数。
public static int largestRectangleArea(int[] heights) { if(heights == null || heights.length == 0) return 0; Stack<Integer> stack = new Stack<>(); int curIndex = 0; int rightSmall = 0; int leftSmall = 0; int maxArea = 0; for (int i = 0; i < heights.length; i++) { while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]) { curIndex = stack.pop();//被弹出的下标,得出左右比它小的数 rightSmall = i; leftSmall = stack.isEmpty()? -1 :stack.peek(); //System.out.println(heights[curIndex] * (rightSmall-leftSmall-1)); maxArea = Math.max(maxArea, heights[curIndex] * (rightSmall-leftSmall-1)); } stack.push(i); } while (!stack.isEmpty()) { curIndex = stack.pop(); leftSmall = stack.isEmpty()? -1 :stack.peek(); maxArea = Math.max(maxArea, heights[curIndex] * (heights.length-leftSmall-1)); } return maxArea; }
2.升级--->给一个二维数组,求"1"能组成的最大矩阵大小
输入: [ ["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"] ] 输出: 6
其实也是根据每一行来遍历,每一行能够向上组成1,然后套入上面的题就能到得结果
public static int maximalRectangle(char[][] matrix) { if (matrix == null || matrix.equals("")|| matrix.length == 0 && matrix[0].length == 0) { return 0; } int maxArea = 0; //按行遍历 for (int i = 0; i < matrix.length; i++) { int[] heights = new int[matrix[0].length];//生成一个新数组 for (int j = 0; j < matrix[0].length; j++) { int num = 0; int curRow = i; while ( curRow >= 0 && matrix[curRow][j] == '1' ) { num++; curRow--; } heights[j] = num; } maxArea = Math.max(largestRectangleArea(heights),maxArea); } return maxArea; } public static int largestRectangleArea(int[] heights) { if(heights == null || heights.length == 0) return 0; Stack<Integer> stack = new Stack<>(); int curIndex = 0; int rightSmall = 0; int leftSmall = 0; int maxArea = 0; for (int i = 0; i < heights.length; i++) { while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]) { curIndex = stack.pop();//被弹出的下标,得出左右比它小的数 rightSmall = i; leftSmall = stack.isEmpty()? -1 :stack.peek(); //System.out.println(heights[curIndex] * (rightSmall-leftSmall-1)); maxArea = Math.max(maxArea, heights[curIndex] * (rightSmall-leftSmall-1)); } stack.push(i); } while (!stack.isEmpty()) { curIndex = stack.pop(); leftSmall = stack.isEmpty()? -1 :stack.peek(); maxArea = Math.max(maxArea, heights[curIndex] * (heights.length-leftSmall-1)); } return maxArea; }
3.山峰篝火问题
这个题意不是记得很清楚了,但就是给定一个数组,数组上的数字组成一个圈,数值代表着山峰的高度,相邻的山峰可以看到篝火,路途矮的山峰也能够看到,