目录
84.柱状图中的最大矩形
方法1.暴力 O(n^3)
public class Solution {
public int largestRectangleArea(int[] heights) {
int maxarea = 0;
for (int i = 0; i < heights.length; i++) {
for (int j = i; j < heights.length; j++) {
int minheight = Integer.MAX_VALUE;
for (int k = i; k <= j; k++)
minheight = Math.min(minheight, heights[k]);
maxarea = Math.max(maxarea, minheight * (j - i + 1));
}
}
return maxarea;
}
}
暴力优化O(n^2)
public class Solution {
public int largestRectangleArea(int[] heights) {
int maxarea = 0;
for (int i = 0; i < heights.length; i++) {
int minheight = Integer.MAX_VALUE;
for (int j = i; j < heights.length; j++) {
minheight = Math.min(minheight, heights[j]);
maxarea = Math.max(maxarea, minheight * (j - i + 1));
}
}
return maxarea;
}
}
方法2.分治
-
确定了最矮柱子以后,矩形的宽尽可能往两边延伸。
-
在最矮柱子左边的最大面积矩形(子问题)。
-
在最矮柱子右边的最大面积矩形(子问题)。
public class Solution {
public int calculateArea(int[] heights, int start, int end) {
if (start > end)
return 0;
int minindex = start;
for (int i = start; i <= end; i++)
if (heights[minindex] > heights[i])
minindex = i;
return Math.max(heights[minindex] * (end - start + 1), Math.max(calculateArea(heights, start, minindex - 1), calculateArea(heights, minindex + 1, end)));
}
public int largestRectangleArea(int[] heights) {
return calculateArea(heights, 0, heights.length - 1);
}
}
方法3.单调栈
-
时间复杂度:O(n) n 个数字每个会被压栈弹栈各一次。
-
空间复杂度: O(n) 用来存放栈中元素。
public class Solution {
public int largestRectangleArea(int[] heights) {
Stack < Integer > stack = new Stack < > ();
stack.push(-1);
int maxarea = 0;
for (int i = 0; i < heights.length; ++i) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i])
maxarea = Math.max(maxarea, heights[stack.pop()] * (i - stack.peek() - 1));
stack.push(i);
}
while (stack.peek() != -1)
maxarea = Math.max(maxarea, heights[stack.pop()] * (heights.length - stack.peek() -1));
return maxarea;
}
}
85.最大矩形
方法1.单调栈
- 时间复杂度 O(MN)
- 空间复杂度 O(M)
class Solution {
public:
int maxArea(vector<int>& matrix) {
stack<int> s;
s.push(-1);
int max_area = 0, height, width;
for(int i = 0; i < matrix.size(); ++i) {
while(s.top() != -1 && matrix[s.top()]>=matrix[i]) {
height = matrix[s.top()];
s.pop();
width = i - s.top() - 1;
max_area = max(max_area, height*width);
}
s.push(i);
}
while(s.top() != -1) {
height = matrix[s.top()];
s.pop();
width = matrix.size() - s.top() - 1;
max_area = max(max_area, height*width);
}
return max_area;
}
int maximalRectangle(vector<vector<char>>& matrix) {
if(matrix.size() == 0) return 0;
int size = matrix[0].size(), max_area = 0;
vector<int>dp(size, 0);
for(int i = 0; i < matrix.size(); ++i) {
for(int j = 0; j < size; ++j) {
//逐行更新dp数组,dp[j]代表第j列的柱子高度
//当matrix[i][j] == '0' ,dp[j] = 0,这很重要,仔细想一下
dp[j] = matrix[i][j] == '1' ? dp[j] + 1 : 0;
}
//逐行更新此时连续柱体形成的矩形面积
max_area = max(max_area, maxArea(dp));
}
return max_area;
}
};
方法2.dp
-
时间复杂度 : O(NM)O(NM)。每次对于
N
的迭代我们会对M
迭代常数次。 -
空间复杂度 : O(M)O(M),
M
是我们保留的额外数组的长度。
class Solution {
public int maximalRectangle(char[][] matrix) {
if(matrix.length == 0) return 0;
int m = matrix.length;
int n = matrix[0].length;
int[] left = new int[n]; // initialize left as the leftmost boundary possible
int[] right = new int[n];
int[] height = new int[n];
Arrays.fill(right, n); // initialize right as the rightmost boundary possible
int maxarea = 0;
for(int i = 0; i < m; i++) {
int cur_left = 0, cur_right = n;
// update height
for(int j = 0; j < n; j++) {
if(matrix[i][j] == '1') height[j]++;
else height[j] = 0;
}
// update left
for(int j=0; j<n; j++) {
if(matrix[i][j]=='1') left[j]=Math.max(left[j],cur_left);
else {left[j]=0; cur_left=j+1;}
}
// update right
for(int j = n - 1; j >= 0; j--) {
if(matrix[i][j] == '1') right[j] = Math.min(right[j], cur_right);
else {right[j] = n; cur_right = j;}
}
// update area
for(int j = 0; j < n; j++) {
maxarea = Math.max(maxarea, (right[j] - left[j]) * height[j]);
}
return maxarea;
}
}