「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战」。
题目
链接:leetcode-cn.com/problems/ma…
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例 1:
**输入:**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.lengthcols == matrix[0].length0 <= row, cols <= 200matrix[i][j]为'0'或'1'
解题思路
- 二维坐标转换成多个柱状图
- 柱子为二维坐标中连续的
'1' - 每个柱状图以 i 号行向右为横坐标,0 号列向上为纵坐标
- 柱子为二维坐标中连续的
- 针对每个柱状图,求其中的最大矩形面积
- 针对任一柱子 top ,向左右找首个严格低于自身的柱子 left/right * 从一维无序数组中的某个元素向左右找首个严格小于/大于自身的元素,可以用单调栈实现 * 本题要找严格低于自身的元素,所以设计单调栈严格递增,出栈时,很容易以 O(1) 时间找到出栈柱子的 left/right 柱子
- 矩形面积就是
heights[top] * width,width = (right - 1) - (left + 1) + 1 - 每个都作为柱子 top ,就能打擂台求出柱状图的的最大矩形面积
- 各个柱状图的最大矩形面积打擂台,得到二维坐标中的最大矩形面积
代码
var maximalRectangle = function(matrix) {
if (!matrix || !matrix.length || !matrix[0].length) return 0
const ROWS = matrix.length, COLS = matrix[0].length
// heightsList[i][j] 表示以 matrix[i] 行向右为横坐标、以 0 号列向上为纵坐标,
// 构成的柱状图中 j 号柱子的高度,柱子为连续的1
const MOD = 2 // heightsList[i] 最多向前依赖 heightsList[i - 1],使用滚动数组节省空间
let heightsList = Array.from({length: MOD}, () => new Array(COLS))
let maxArea = 0
for (let i = 0; i < ROWS; ++i) { // O(ROWS)
for (let j = 0; j < COLS; ++j) { // O(COLS)
heightsList[i % MOD][j] = matrix[i][j] === '1' ?
(i - 1 >= 0 ? heightsList[(i - 1) % MOD][j] : 0) + 1 :
0
}
maxArea = Math.max(maxArea, getMaxArea(heightsList[i % MOD]))
}
// console.log(heightsList)
return maxArea
// 求柱状图中的最大矩形面积
// 对任一柱子 top ,向左右找到首个严格低于自身的柱子 left/right
// 矩形面积就是 heights[top] * width
// width = (right - 1) - (left + 1) + 1
// 用单调栈实现向左右找首个柱子,单调严格递增
function getMaxArea(heights) {
// NOTICE:
// 前哨兵:防止栈空,防止越界
// 后哨兵:确保每个入栈的元素最终都经历出栈
// 严格递增,前哨兵要小于后哨兵,否则后哨兵会让栈空,导致求 left 时越界
heights = [-2, ...heights, -1]
const N = heights.length
let maxArea = 0, stack = []
for (let i = 0; i < N; ++i) { // O(COLS + 2) = O(COLS) ,因为每个元素都只经历一次入栈、出栈
while (stack.length) {
const top = stack[stack.length - 1]
if (heights[i] > heights[top]) break
stack.pop()
const left = stack[stack.length - 1], right = i
const width = (right - 1) - (left + 1) + 1
maxArea = Math.max(
maxArea,
width * heights[top]
)
}
stack.push(i)
}
return maxArea
}
}