【代码训练营】day60 | 84.柱状图中最大的矩形

所用代码 java

柱状图中的最大矩形 LeetCode 84

题目链接:柱状图中的最大矩形 LeetCode 84 - 困难

思路

和上面那个接雨水的题类似,我们找的是左右比自己小的值。要注意的是首位都应该加一个0,以避免数据本身是单调的造成没法计算结果。

单调栈解法:

class Solution {
    public int largestRectangleArea(int[] heights) {
        Deque<Integer> stack = new LinkedList<>();
        // 新建一个数组,首位填0,以防止数组是单调递增或递减无法计算高度的情况
        int[] newHeights = new int[heights.length + 2];
        newHeights[0] = 0;
        newHeights[newHeights.length-1] = 0;
        for (int i = 0; i < heights.length; i++) {
            newHeights[i+1] = heights[i];
        }// 接收结果
        int result = 0;
        stack.push(newHeights[0]);
        for (int i = 1; i < newHeights.length; i++) {
            if (newHeights[i] > newHeights[stack.peek()]){
                stack.push(i);
            }else if (newHeights[i] == newHeights[stack.peek()]){
                // 这里可加可不加
                stack.pop();
                stack.push(i);
            }else {
                while (!stack.isEmpty() && newHeights[i] < newHeights[stack.peek()]){
                    // 取出栈顶元素
                    int mid = stack.pop();
                    // 高度就是本身
                    int h = newHeights[mid];
                    // 找到的是两边都比mid较小的,两边都不能要,所以要多减一个1
                    int w = i - stack.peek() - 1;
                    result = Math.max(result, h * w);
                }
                System.out.println("result = " + result);
                stack.push(i);
            }
        }
        return result;
    }
}

暴力解法: 超时了!

class Solution {
    public int largestRectangleArea(int[] heights) {
        int sum = 0;
        for (int i = 0; i < heights.length; i++) {
            int left = i;
            int right = i;
            for (;left >= 0;left--){
                if (heights[left] < heights[i]) break;
            }
            for (;right < heights.length; right++){
                if (heights[right] < heights[i]) break;
            }int w = right - left - 1;
            int h = heights[i];
            sum = Math.max(sum, w*h);
        }return sum;
    }
}

双指针优化暴力: 空间换时间速度较快

class Solution {
    public int largestRectangleArea(int[] heights) {
        int result = 0;
        // 找到每个位置左右第一个比自己小的下标
        int len = heights.length;
        int[] left = new int[len];
        int[] right = new int[len];// 找左边第一个比自己小的下标
        left[0] = -1; // 边界为-1,初始化以防止进入死循环
        for (int i = 1; i < len; i++) {
            int t = i-1;
            // 当第i个元素小于的第t个元素,就将t=left[t],
            // 意思是下标为t的左边第一个小于该值的下标,赋给t再比较,不断循环找出最小值
            while (t>=0 && heights[t] >= heights[i]){
                t = left[t];
            }
            left[i] = t;
        }// 找右边第一个比自己小的下标
        right[len - 1] = len; // 初始话,右边界最小为自己,只有一个元素才会1-(-1)-1=1
        for (int i = len - 2; i>=0; i--){
            int t = i + 1;
            while (t<len && heights[t] >= heights[i]){
                t = right[t];
            }
            right[i] = t;
        }for (int i = 0; i < len; i++) {
            int sum = heights[i] * (right[i] - left[i] - 1);
            result = Math.max(sum,result);
        }return result;
    }
}

总结

本题和接雨水的题一模一样,接雨水是找两边最大值,求面积是找第一个最小值,方法异曲同工,都是使用单调栈来接收和弹出元素,但是求面积使用的是单调递减的栈,才能找到第一个比自己小的数。

你可能感兴趣的:(代码训练营,leetcode,算法,java,数据结构)