LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)相关的知识,希望对你有一定的参考价值。


​welcome to my blog​

LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)

题目描述

Given a 2D binary matrix filled with 0s and 1s, find the largest rectangle containing only 1s and return its area.

Example:

Input:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
Output: 6
class Solution 
public int maximalRectangle(char[][] matrix)
if(matrix.length==0 || matrix[0].length==0)
return 0;

int n = matrix.length, m = matrix[0].length;
int[] height = new int[m];
int res=0, cur=0;
Stack<Integer> s = new Stack<>();
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
height[j] = matrix[i][j]==1? height[j]+1 : 0;

cur = core(height, s);
res = Math.max(res, cur);

return res;


private int core(int[] height, Stack<Integer> s)
s.clear();
s.push(-1);
int res=0, cur;
//遍历阶段; 每个元素进栈一次 (可能会出栈一次, 或者在清算阶段时出栈一次)
for(int i=0; i<height.length; i++)
while(s.peek()!=-1 && height[s.peek()] > height[i])
int j = s.pop();
res = Math.max(res, (i-s.peek()-1)*height[j]);

s.push(i);

//清算阶段: 数组中的最后一个元素一定在栈顶
while(s.peek()!=-1)
int j = s.pop();
res = Math.max(res, (height.length - 1 -s.peek())*height[j]);

return res;

第一次做, 使用动态规划, 一层一层处理; 结合最下面的图去理解递推公式; 速度最快, 但是不便于理解, 还要是牢牢掌握单调栈的解法

/*
动态规划版本, 按层计算
对于当前层, 遍历每一列, 对于某一列, 找出该列左右两侧离该列最近且比该列小的柱子
*/
import java.util.Arrays;

class Solution
public int maximalRectangle(char[][] matrix)
if(matrix==null || matrix.length==0 || matrix[0].length==0)
return 0;
//
int rows = matrix.length;
int cols = matrix[0].length;
//对于某一层的某一列, left[j]表示j左边离j最近的并且比matrix[][j]小的柱子
int[] left = new int[cols];
Arrays.fill(left, -1);
//对于某一层的某一列, right[j]表示j右边离j最近的并且比matrix[][j]小的柱子
int[] right = new int[cols];
Arrays.fill(right, cols);
//以某一层的某个点为底, 往上有多少个连续的1, 包括底在内
int[] heights = new int[cols];
//newest0表示某一列中, 最靠近j的0的列索引
int res=0, curr, newest0=-1;
for(int i=0; i<rows; i++)
//以当前层的各个点为底, 往上有多少个连续的1
for(int j=0; j<cols; j++)
heights[j] = matrix[i][j]==1 ? heights[j]+1 : 0;

//更新left, 找出matrix[][j]左边距离j最近的并且比matrix[][j]小的柱子
newest0 = -1;
for(int j=0; j<cols; j++)
//理解下面的语句要结合图, 否则太抽象了
//当前位置是1, 对应的left[j]要么不变, 要么更靠近j了
//更靠近j是因为在靠近j的位置出现了0
if(matrix[i][j] == 1)
left[j] = Math.max(left[j], newest0);

//当前位置是0, 不存在比该位置对应值更小的柱子了
else
left[j] = -1;//这里赋值为-1相当于初始化, 让下一行使用; 不能赋成大于等于0的值
newest0 = j;


//更新right
newest0 = cols;
for(int j=cols-1; j>=0; j--)
if(matrix[i][j]==1)
right[j] = Math.min(right[j], newest0);

//当前位置为0, 不存在比该位置对应值更小的柱子了
else
right[j] = cols;//这里赋成cols相当于初始化, 让下一行使用; 不能赋成小于cols的值
newest0 = j;


//计算面积
for(int j=0; j<cols; j++)
curr = (right[j] - left[j] - 1) * heights[j];
res = Math.max(res, curr);


return res;

第一次做, 多次使用单调栈结构; 栈底到栈顶递增; 注意计算面积时,为什么宽度不能用index求,而必须用s.peek()求; char与ascii与整数的细节, 看代码

/*
使用单调栈: 栈底到栈顶递增
和84题很像, 使用84单调栈的处理方式
*/
import java.util.Stack;

class Solution
public int maximalRectangle(char[][] matrix)
if(matrix==null || matrix.length==0 || matrix[0].length==0)
return 0;
//
int[] heights = new int[matrix[0].length];
int res = 0, curr;
Stack<Integer> s = new Stack<>();
for(int i=0; i<matrix.length; i++)
for(int j=0; j<matrix[0].length; j++)
//统计以matrix[i][j]往上有多少个连续的1, 包括matrix[i][j]自己
//ascii: 48是0, 49是1
heights[j] = matrix[i][j]==49? heights[j]+1 : 0;
/*
这里也可以写成
heights[j] = matrix[i][j]==1 ? heights[j]+1 : 0;
*/

curr = monotonousStack(heights, s);
res = Math.max(res, curr);

return res;

public int monotonousStack(int[] heights, Stack<Integer> s)
//由于矩阵的每一行用的都是同一个栈, 所以使用前先清空一下栈
s.clear();

//单调栈: 栈底到栈顶递增
//栈中存索引; 压入参考值-1
s.push(-1);
//遍历阶段
int res=0, curr, index;
for(int i=0; i<heights.length; i++)
while(s.peek()!=-1 && heights[s.peek()] > heights[i])
//弹出栈顶元素
index = s.pop();
//计算面积
//计算宽度时必须用s.peek(),不能用index! 因为从index处也许能够向左扩展(和左神讲的思路一致); 想不明白用用[3,1,3,2,2]进行debug
curr = heights[index] * (i - s.peek() - 1);
//
res = Math.max(res, curr);

s.push(i);

//清算阶段
while(s.peek()!=-1)
//heights[index]是index,index+1,...,heights.length-1范围上值最小的
index = s.pop();
//计算面积
curr = heights[index] * (heights.length-1 - s.peek());
//
res = Math.max(res, curr);

return res;

按层来看, 这道题就是84题的加强版

84题图

LeetCode

85题图, ​​图片来源​

LeetCode


以上是关于LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode Top 100 Liked Questions 85. Maximal Rectangle (Java版; Hard)

LeetCode Top 100 Liked Questions 10.Regular Expression Matching (Java版; Hard)

LeetCode Top 100 Liked Questions 142. Linked List Cycle II (Java版; Medium)

LeetCode Top 100 Liked Questions 98. Validate Binary Search Tree (Java版; Medium)

LeetCode Top 100 Liked Questions 124. Binary Tree Maximum Path Sum (Java版; Hard)

LeetCode - #207 课程表(Top 100)