【前端er每日算法】单调栈-柱状图中最大的矩形

118 阅读1分钟

题目 84. 柱状图中最大的矩形

思路

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

方法1 双指针

最大面积等于遍历每一个柱子,包含当前柱子形成的矩形的最大面积。计算每一个柱子左侧比它小的index,右侧比它小的index,然后再遍历,每个的面积等于当前柱子的高度 * (右侧-左侧-1),取最大值。

/**
 * @param {number[]} heights
 * @return {number}
 */
var largestRectangleArea = function(heights) {
    const len = heights.length;
    const minLeftArr = new Array(len);
    const minRightArr = new Array(len);

    minLeftArr[0] = -1;
    for (let i = 1; i < len; i++) {
        let j = i - 1;
        while(j >= 0 && heights[j] >= heights[i]) {
            j = minLeftArr[j];
        }
        minLeftArr[i] = j;
    }
    minRightArr[len-1] = len;
    for (let i = len - 2; i >= 0; i--) {
        let j = i + 1;
        while(j < len && heights[j] >= heights[i]) {
            j = minRightArr[j];
        }
        minRightArr[i] = j;
    }
    let result = 0;
    for (let i = 0; i < len; i++) {
        const sum = heights[i] * (minRightArr[i] - minLeftArr[i] - 1);
        result = Math.max(sum, result);
    }
    return result;
};

方法2 单调栈

接雨水题目类似,但是栈是从大到小的。

  • 如果元素大于栈顶元素,则入栈
  • 元素等于栈顶元素,栈顶元素先出栈,再入栈当前元素
  • 元素小于栈顶元素,则开始计算,执行while循环,每次计算当前栈顶元素的最大矩形,出栈该元素,直到遇到大于栈顶的元素,将该元素入栈。

兼容递增或者递减的序列,将height前后插入0形成新的数组

var largestRectangleArea = function(heights) {
    heights = [0, ...heights, 0];
    const len = heights.length;
    const stack = [];
    stack.push(0);

    let result = 0;
    for (let i = 1; i < len; i++) {
        const val = heights[i];
        let topIndex = stack[stack.length - 1];
        let top = heights[topIndex];
        if (val >= top) {
            stack.push(i);
        } else {
            while (stack.length && val < heights[topIndex]) {
                const midIndex = stack.pop();
                if (stack.length) {
                    const left = stack[stack.length - 1];
                    const right = i;
                    const w = right - left - 1;
                    const h = heights[midIndex];
                    result = Math.max(result, w * h);
                    topIndex = left;
                }
            }
            stack.push(i);
        }
    }
    return result;
}