解法1:
一个思路就是这个可以看作84. 柱状图中最大的矩形的扩展,这道题的二维矩阵每一层向上都可以看做一个直方图,输入矩阵有多少行,就可以形成多少个直方图,对每个直方图都调用 84. 柱状图中最大的矩形 中的方法,就可以得到最大的矩形面积。
class Solution {
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
if (m == 0) return 0;
int n = matrix[0].length;
if (n == 0) return 0;
int[] height = new int[n];
int ans = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == \'0\') height[j] = 0;
else if (matrix[i][j] == \'1\') height[j] += 1;
}
ans = Math.max(largestRectangleArea(height), ans);
}
return ans;
}
public int largestRectangleArea(int[] heights) {
if (heights.length == 0) return 0;
Stack<Integer> stack = new Stack<>();
int max = 0;
for (int i = 0; i < heights.length; i++) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
int tmp = stack.pop();
// 把当前的tmp木板作为最短木板,看能组成的最大面积是多少
max = Math.max(max, heights[tmp] * (stack.empty() ? i : i - stack.peek() - 1));
}
stack.push(i);
}
int tmp = 0;
int len = heights.length;
while (!stack.isEmpty()) {
tmp = stack.pop();
max = Math.max(max, heights[tmp] * (stack.empty() ? len : len - stack.peek() - 1));
}
return max;
}
}
解法2:
另外一个思路就是,想办法如何很方便的表示出一个矩形。比如说,对于以(i,j)点为右下角的矩形。
大家可以先想暴力思路,实际上大部分的优化思路,都是以暴力思路基础而来的。
暴力思路:枚举(i,j)为一个矩形的右下角,然后以(i,j)为起点,向左、向上看,能组成的最大矩形是什么。时间复杂度为O(n^4)。
仔细观察一下,其实在向左、向上看,能组成的最大矩形是什么这个过程中,是存在重复计算的。也就是说当我们算完点(i,j)后,(i+1,j)点,我们或许只需要看第i+1行就可以了。
所以,我们可否用动态规划来做呢?
有个思路很巧妙:
height数组和上面一样,height表示高,这里的left数组表示左边界是1的位置,right数组表示右边界是1的位置,那么对于任意一行的第j个位置,矩形为(right[j] - left[j]) * height[j]
具体参考:算法学习之动态规划 85. Maximal Rectangle
文章里讲的方法我大概是懂了,其核心思路是从第一行开始一行一行地处理,然后其left与right数组巧妙的保存了上层的状态,使得其能表示出矩阵左边界或者右边界的位置,进而就很方便的表示出了一个矩形了
但是,我觉得我是想不出来这个思路的- -。。非常的巧妙啊