单调栈

单调栈是一个比较常用也很好用的一个结构,它的作用是找到某个数的左右边比它大/小的最近的数.

 

 压入栈时,如果即将压入的数值会破坏规则,栈里的数依次弹出,直到栈为空或者不会破坏规则。

弹出数时就能得到结果-->右边最近比它大==因为谁而被弹出

            左边最近比它大==栈里它的下面值

面试题:

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.山峰篝火问题

这个题意不是记得很清楚了,但就是给定一个数组,数组上的数字组成一个圈,数值代表着山峰的高度,相邻的山峰可以看到篝火,路途矮的山峰也能够看到,

posted @ 2020-10-05 01:03  拿着放大镜看世界  阅读(127)  评论(0编辑  收藏  举报