算法练习day52

64 阅读1分钟

柱状图中最大矩形

暴力解法

/**
 * @param {number[]} heights
 * @return {number}
 */
var largestRectangleArea = function(heights) {
    let result = 0
    for(let i = 0; i < heights.length;i++) {
        let left = i, right = i
        while(left >= 0) {
            if(heights[left] < heights[i]) {
                break
            }
            left--
        }
        while(right < heights.length) {
            if(heights[right] < heights[i]) {
                break
            }
            right++
        }
        let w = right - left - 1
        result = Math.max(result, w * heights[i])
    }
    return result
};

双指针解法

var largestRectangleArea = function (heights) {
    let result = 0
    let minLeftIndexMap = new Array(heights.length)
    minLeftIndexMap[0] = -1
    let minRightIndexMap = new Array(heights.length)
    minRightIndexMap[heights.length - 1] = heights.length
    for (let i = 1; i < heights.length; i++) {
        let left = i - 1
        while (left >= 0 && heights[left] >= heights[i]) {
            left = minLeftIndexMap[left]
        }
        minLeftIndexMap[i] = left
    }
    for (let i = heights.length - 2; i >= 0; i--) {
        let right = i + 1
        while (right < heights.length && heights[right] >= heights[i]) {
            right = minRightIndexMap[right]
        }
        minRightIndexMap[i] = right
    }

    let maxArea = 0
    for (let i = 0; i < heights.length; i++) {
        let area = heights[i] * (minRightIndexMap[i] - minLeftIndexMap[i] - 1)
        maxArea = Math.max(maxArea, area)
    }

    return maxArea
};

单调栈

接雨水的思路是找柱子左右两边第一个大于该柱子高度的柱子,而本题是找左右两边小于该柱子的柱子

只有栈里面从栈头到栈底是从大到小的顺序,才能保证栈顶元素找到两边第一个小于栈顶元素的柱子

栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求的最大面积的高度和宽度

三种情况

  1. 当遍历的元素height[i] > heights[st.top()],入栈
  2. 当遍历的元素height[i] === heights[st.top()],入栈
  3. 当遍历的元素height[i] < heights[st.top()],用while出栈并计算
var largestRectangleArea = function (heights) {
    let stack = [0]
    let result = 0
    heights.unshift(0)
    heights.push(0)
    for(let i = 1; i < heights.length;i++) {
        while(stack.length && heights[i] < heights[stack[stack.length - 1]]) {
            let left = stack.pop()
            let w = i - stack[stack.length - 1] - 1
            let h = heights[left]
            result = Math.max(result, w * h)
        }
        stack.push(i)
    }
    return result
};