[JavaScript / leetcode] 85. 最大矩形

129 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

每日刷题 2022.10.03

题目

  • 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

示例

  • 示例1

image.png

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。
  • 示例2
输入: matrix = []
输出: 0
  • 示例3
输入: matrix = [["0"]]
输出: 0
  • 示例4
输入: matrix = [["1"]]
输出: 1
  • 示例5
输入: matrix = [["0","0"]]
输出: 0

提示

  • rows == matrix.length
  • cols == matrix[0].length
  • 1 <= row, cols <= 200
  • matrix[i][j] 为 '0' 或 '1'

解题思路

  • 类似的题目84. 柱状图中最大的矩形, 都是单调栈的运用题目。
  • 整体思路:找到左上、右下,判中间,算面积。
  • 具体实现:
    • 遍历所有点,作为左上。
    • 向右向下找最长边。
    • 限定一个宽度,从左往右找,找到最后一个满足的竖边。则得到一个长方形。计算面积。
    • 宽度加一,相同方法,再找到一个,计算面积。保留最大的。
  • 如果按可能的最大宽度和最大长度算出来的最大面积都比已知最大面积小,就不用继续了。

预处理

  • 预处理matrix[i][j]左边连1的个数(包括matrix[i][j]),并将结果存放在left[i][j]中。
  • 枚举所有以matrix[i][j]为右下角的矩形,那么该矩形的最大宽度一定是left[i][j],left[i - 1][j]⋯left[k][j], 0 <= k <= i的最小值。

AC代码

/**
 * @param {character[][]} matrix
 * @return {number}
 */
var maximalRectangle = function(matrix) {
  // 还可以使用前面的单调栈数据结构
  // 需要先统计每一层的连续的大小,最后将总的进行比较
  let maxx = 0, n = matrix.length, m = matrix[0].length, r = new Array(m).fill(0);
  for(let i = 0; i < n; i++) {
    for(let j = 0; j < m; j++) {
      if(matrix[i][j] === '1') r[j]++;
      else r[j] = 0;
    }
    // 调用一次单调栈,查找最大的
    maxx = Math.max(maxx, sole(r));
  }
  return maxx;
  function sole(cur) {
    // console.log('start:::', cur)
    let stack = [], left = new Array(m).fill(-1);
    for(let z = m - 1; z >= 0; z--) {
      while(stack.length != 0 && cur[stack[stack.length - 1]] > cur[z]) {
        let t = stack.pop();
        left[t] = z;
      }
      stack.push(z);
    }
    // console.log('left:::', left)
    // 找到了左边的,还需要查找右边的
    let right = new Array(m).fill(m);
    for(let z = 0; z < m; z++) {
      while(stack.length != 0 && cur[stack[stack.length - 1]] > cur[z]) {
        let t = stack.pop();
        right[t] = z;
      }
      stack.push(z);
    }
    // console.log('right:::', right)
    let ans = 0;
    for(let z = 0; z < m; z++) {
      if(cur[z] != 0) ans = Math.max(ans, (right[z] - left[z] - 1) * cur[z]);
      // console.log('ans:::', ans)
    }
    return ans;
  }
};