柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]
。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10
个单位
示例:
输入: [2,1,5,6,2,3]
输出: 10
方法一:暴力
固定高度,向两边找边
public int largestRectangleArea(int[] heights) {
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
int left = i, right = i;
while (left >= 0 && heights[left] >= heights[i]) {
left--;
}
while (right < heights.length && heights[right] >= heights[i]) {
right++;
}
maxArea = Math.max(maxArea, heights[i] * (right - left - 1));
}
return maxArea;
}
固定边
public int largestRectangleArea(int[] heights) {
int maxArea = 0;
for (int i = 0; i < heights.length; i++) {
int minHeight = heights[i];
for (int j = i; j < heights.length; j++) {
minHeight = Math.min(minHeight, heights[j]);
maxArea = Math.max(maxArea, minHeight * (j - i + 1));
}
}
return maxArea;
}
方法二:单调栈
public int largestRectangleArea(int[] heights) {
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < heights.length; i++) {
while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) {
int height = heights[stack.pop()];
int width;
if (stack.isEmpty()) {
width = i;
} else {
width = i - stack.peek() - 1;
}
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
while (!stack.isEmpty()) {
int height = heights[stack.pop()];
int width;
if (stack.isEmpty()) {
width = heights.length;
} else {
width = heights.length - stack.peek() - 1;
}
maxArea = Math.max(maxArea, height * width);
}
return maxArea;
}
哨兵
public int largestRectangleArea(int[] heights) {
int len = heights.length;
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
int[] newHeights = new int[len + 2];
System.arraycopy(heights, 0, newHeights, 1, len);
heights = newHeights;
len += 2;
stack.push(0);
for (int i = 1; i < len; i++) {
while (heights[i] < heights[stack.peek()]) {
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
最大矩形
给定一个仅包含 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
方法一:暴力
遍历每个点pos,以pos为矩形的右下角向左上寻找矩形,不断更新最大矩形
怎么找出这样的矩阵呢?如下图,如果我们知道了以这个点结尾的连续 1 的个数的话,问题就变得简单了。
以橙色的点为右下角,高度为 1:
高度为 2:
高度为 3:
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int m = matrix.length, n = matrix[0].length;
// 每个点左边(包括自己)连续1的数量
int[][] left = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '1') {
left[i][j] = (j > 0 ? left[i][j - 1] : 0) + 1;
}
}
}
int maxArea = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 在向上遍历的过程中,记录最小宽度
int minWidth = left[i][j];
for (int k = i; k >= 0; k--) {
// 如果遇到了0,就没必要再向上找矩形了
if (matrix[k][j] == '0') {
break;
}
minWidth = Math.min(minWidth, left[k][j]);
maxArea = Math.max(maxArea, minWidth * (i - k + 1));
}
}
}
return maxArea;
}
时间复杂度O(m2n)
方法二:单调栈
参考上一题,记录每一个点上边(包括自己)连续一个个数,将这个个数看做高度,再遍历每一行,就算柱状图中最大的矩形
将之前的left数组改为pre数组
public int maximalRectangle(char[][] matrix) {
if (matrix == null || matrix.length == 0) {
return 0;
}
int m = matrix.length, n = matrix[0].length;
int[][] pre = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '1') {
pre[i][j] = (i > 0 ? pre[i - 1][j] : 0) + 1;
}
}
}
int maxArea = 0;
for (int i = 0; i < m; i++) {
maxArea = Math.max(maxArea, largestRectangleArea(pre[i]));
}
return maxArea;
}
public int largestRectangleArea(int[] heights) {
int len = heights.length;
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
int[] newHeights = new int[len + 2];
System.arraycopy(heights, 0, newHeights, 1, len);
heights = newHeights;
len += 2;
stack.push(0);
for (int i = 1; i < len; i++) {
while (heights[i] < heights[stack.peek()]) {
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
时间复杂度O(mn)