前言
最大面积有长和宽决定,然后去考虑如何控制长宽。
一、案例
1、直方图最大矩阵面积
2、矩阵中的最大矩阵面积
二、题解
1、问题拆解+单调栈
单调栈思想,单调递增栈,当遇到小值时,就计算在栈中小于此值的包裹面积,再比较大小。毕竟单调增的直方图很好计算包裹面积。
为什么大的要出栈,因为大的对于增加宽度已经没有意义,宽度到极限了,毕竟这些小的和大的围起来有空洞,所以继续往后走。
package com.xhu.offer.offerII;
import java.util.ArrayList;
import java.util.List;
//直方图最大矩阵面积
public class LargestRectangleArea {
//双指针问题
public int largestRectangleArea(int[] heights) {
//单调栈思想,单调递增栈,当遇到小值时,就计算在栈中小于此值的包裹面积,再比较大小。毕竟单调增的直方图很好计算包裹面积。
//为什么大的要出栈,因为大的对于增加宽度已经没有意义,宽度到极限了,毕竟这些小的和大的围起来有空洞,所以继续往后走。
//拆解问题:最大面积有长和宽决定,然后去考虑如何控制长宽。
//这个代码把人折磨死,究其原因,都是因为思想不清晰不专注导致逻辑不连贯导致的逻辑不严谨,修修补补很久。
if (heights.length == 1) return heights[0];
int len = heights.length;
int begin = 0, max = Integer.MIN_VALUE;
List<Integer> cache = new ArrayList<>();
cache.add(0);
for (int i = 1; i < len; i++) {
int idx = cache.get(cache.size() - 1);
if (heights[i] >= heights[idx]) {
cache.add(i);
continue;
}
while (!cache.isEmpty()) {
int k = cache.get(cache.size() - 1);
if (heights[k] > heights[i]) {
int r = cache.size() > 1?cache.get(cache.size() -2):-1;
int t = (i - r - 1) * heights[k];
max = max < t ? t : max;
cache.remove(cache.size() - 1);
continue;
}
break;
}
cache.add(i);
}
int m = cache.get(cache.size() - 1);
while (cache.size() > 1) {
int t = (m - cache.get(cache.size() - 2)) * heights[cache.get(cache.size() - 1)];
System.out.println(heights[cache.size()-1]);
max = max < t ? t : max;
cache.remove(cache.size() - 1);
}
int t = heights[cache.get(0)] * len;
return max < t ? t : max;
}
}
2、问题转化、举一反三
可以把矩阵当成直方图去寻找最大围成面积
package com.xhu.offer.offerII;
import java.util.ArrayList;
import java.util.List;
//矩阵中最大的矩形
public class MaximalRectangle {
public int maximalRectangle(String[] matrix) {
if (matrix.length == 0) return 0;
int len = matrix.length;
int[][] cache = new int[len][];
int max = 0;
for (int i = 0; i < len; i++) {
int length = matrix[i].length();
cache[i] = new int[length];
for (int j = 0; j < length; j++) {
cache[i][j] = matrix[i].charAt(j) == '0' ? 0 : i > 0 ? cache[i - 1][j] + 1 : 1;
int l = largestRectangleArea(cache[i]);
max = max < l ? l : max;
}
}
return max;
}
//双指针问题
public int largestRectangleArea(int[] heights) {
//单调栈思想,单调递增栈,当遇到小值时,就计算在栈中小于此值的包裹面积,再比较大小。毕竟单调增的直方图很好计算包裹面积。
//为什么大的要出栈,因为大的对于增加宽度已经没有意义,宽度到极限了,毕竟这些小的和大的围起来有空洞,所以继续往后走。
//拆解问题:最大面积有长和宽决定,然后去考虑如何控制长宽。
//这个代码把人折磨死,究其原因,都是因为思想不清晰不专注导致逻辑不连贯导致的逻辑不严谨,修修补补很久。
if (heights.length == 1) return heights[0];
int len = heights.length;
int begin = 0, max = Integer.MIN_VALUE;
List<Integer> cache = new ArrayList<>();
cache.add(0);
for (int i = 1; i < len; i++) {
int idx = cache.get(cache.size() - 1);
if (heights[i] >= heights[idx]) {
cache.add(i);
continue;
}
while (!cache.isEmpty()) {
int k = cache.get(cache.size() - 1);
if (heights[k] > heights[i]) {
int r = cache.size() > 1 ? cache.get(cache.size() - 2) : -1;
int t = (i - r - 1) * heights[k];
max = max < t ? t : max;
cache.remove(cache.size() - 1);
continue;
}
break;
}
cache.add(i);
}
int m = cache.get(cache.size() - 1);
while (cache.size() > 1) {
int t = (m - cache.get(cache.size() - 2)) * heights[cache.get(cache.size() - 1)];
System.out.println(heights[cache.size() - 1]);
max = max < t ? t : max;
cache.remove(cache.size() - 1);
}
int t = heights[cache.get(0)] * len;
return max < t ? t : max;
}
}
总结
1)单调栈的思想应用于这些数组关于大小的问题。
2)这个代码把人折磨死,究其原因,都是因为思想不清晰不专注导致逻辑不连贯导致的逻辑不严谨,修修补补很久。
3)观察问题的特点,将问题进行转化与以前想关的问题。
参考文献
[1] LeetCode 原题