力扣 85. 最大矩形
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
方案一:类比力扣 84题,将矩阵压缩成一维数组,遍历矩阵,从第一行开始,每次加一行,将其压缩成一维数组后再用 力扣 84. 柱状图中最大的矩形 的解法即可。
type rect struct {
width int
height int
}
func maximalRectangle(matrix [][]byte) int {
ans := 0
// 用 cols 长度定一个一个数组(沿用柱状图中最大的矩形的解题思路)
// 因为题目保证 1 <= row, cols <= 200
heights := make([]int, len(matrix[0]))
// 遍历每行元素
for _, raw := range matrix {
for i, v := range raw {
// 如果当前值为 0,类比柱状图中的 height[i] = 0
// (就算此前累积了高度遇到当前的 0 也会断开,变得不连续)
if v == '0' {
heights[i] = 0
} else { // 否则 height[i] 应该等于之前累积的高度再加上当前的 1
heights[i]++
}
}
ans = max(ans, largestRectangleArea(heights))
}
return ans
}
// largestRectangleArea leetcode84. 柱状图中最大的矩形解。
func largestRectangleArea(heights []int) int {
ans := 0
// 构建单调递增栈,高的柱子遇到矮的柱子可以贡献自身高度
stk := make([]*rect, 0, len(heights))
// 在柱形图末尾补零,保证触发单调递增栈的出栈逻辑
heights = append(heights, 0)
for _, h := range heights {
acculmatedWidth := 0
// 如果栈不空,并且无法构成递增(此时需要出栈栈顶)
for len(stk) > 0 && stk[len(stk) - 1].height > h {
// 取栈顶
top := stk[len(stk) - 1]
// 累积宽度(高的柱子贡献了自己的宽度)
acculmatedWidth += top.width
// 计算最大值
ans = max(ans, acculmatedWidth * top.height)
// 出栈
stk = stk[:len(stk) - 1]
}
// +1 加的是自身的宽度
acculmatedWidth += 1
// 入栈当前矩形
// acculmatedWidth 中包含了如果无法构成单调增而出栈的柱子的宽度
stk = append(stk, &rect{
width: acculmatedWidth,
height: h,
})
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
- 时间复杂度:O(row * cols),因为需要遍历矩阵中所有元素,虽然遍历途中有入栈出栈的遍历操作(每个元素最多出入一次),但是均摊后时间复杂度还是在 O(row * cols)。
- 空间复杂度:O(cols),因为主函数里申请了长度为 cols 的数组,循环中的子函数使用了长度不超过 cols 的单调栈,所以总空间复杂度为 O(cols)。