一、棧
承接Leetcode 84,柱狀圖算最大矩形面積,把該題入參改為柱狀圖高度即可
PS:這版本手搓int[]做棧和直接用ArrayDeque做棧,結果僅差2ms;但題84相差近15ms。
public int maximalRectangle(char[][] matrix) {
if (matrix.length == 0) {
return 0;
}
int a = matrix[0].length; // row
int b = matrix.length;
int[] heights = new int[a + 2];
heights[0] = -1;
heights[b + 1] = -1;
int max = 0;
for (int j = 0; j < b; j++) {
// 構建柱狀圖heights
for (int i = 0; i < a; i++) {
boolean isZero = matrix[j][i] == '0';
heights[i + 1] = isZero ? 0 : heights[i + 1] + 1;
}
max = Math.max(max, largestRectangleArea(heights));
}
return max;
}
// 參考leetcode84題解
public int largestRectangleArea(int[] heights) {
int max = 0;
Deque<Integer> stack = new ArrayDeque<>();
stack.push(0);
for (int i = 1; i < heights.length; i++) {
int curH = heights[i];
while (curH < heights[stack.peek()]) {
int confirmIdx = stack.pop();
max = Math.max(max, heights[confirmIdx] * (i - stack.peek() - 1));
}
stack.push(i);
}
return max;
}
二、dp + 剪枝
自己想的第一版,記錄一下。想法就是如何用到dp,那就是左邊這個點,和上面這個點 ==> 當前這個點。
dp存的是所有可能最大矩形的左上角點的合集。
分五種情況討論
左為null,上為null => 自己
左為null,上不為null => 上的最高點
左不為null,上為null => 左的最左點
左不為null,上不為null,左上為null => 上的最高點 + 左的最做點
左不為null,上不為null,左上不為null =>
- 看左邊所有的點,取其y值與上的最高點的最小值(因為左邊所有點是從最左點遍歷的,因此一旦其y值<=最高點的最小值,即可剪枝)
- 若左邊所有點的y值都小於最高點,則+上的最高點(否則就已經涵蓋,不需要另外再加,算是剪枝的一部分)
class Solution {
public int maximalRectangle(char[][] matrix) {
if (matrix.length <= 0) {
return 0;
}
int aSize = matrix[0].length;
int bSize = matrix.length;
Batch[] first = new Batch[aSize + 1];
Batch[] second = new Batch[aSize + 1];
int maxSize = 0;
for (int j = 1; j < bSize + 1; j++) {
for (int i = 1; i < aSize + 1; i++) {
if (matrix[j - 1][i - 1] == '0') {
second[i]=null;
continue;
}
if (second[i - 1] == null && first[i] == null) {
second[i] = Batch.initSingle(i, j);
} else if (second[i - 1] == null && first[i] != null) {
second[i] = Batch.initUp(first[i], i, j);
} else if (second[i - 1] != null && first[i] == null) {
second[i] = Batch.initLeft(second[i - 1], i, j);
} else {
second[i] = Batch.merge(second[i - 1], first[i], first[i - 1], i, j);
}
maxSize = Math.max(maxSize, second[i].calSize(i, j));
}
for (int i = 1; i < aSize + 1; i++) {
first[i] = second[i];
}
}
return maxSize;
}
static class Batch {
int minX;
int minY;
List<Point> list;
public static Batch init() {
Batch batch = new Batch();
batch.list = new ArrayList<>();
return batch;
}
public static Batch initSingle(int x, int y) {
Batch batch = init();
batch.list.add(Point.init(x, y));
batch.minX = x;
batch.minY = y;
return batch;
}
public static Batch initUp(Batch other, int i, int j) {
return initSingle(i, other.minY);
}
public static Batch initLeft(Batch other, int i, int j) {
return initSingle(other.minX, j);
}
public static Batch merge(Batch left, Batch up, Batch leftUp, int i, int j) {
Batch b = Batch.init();
b.minX = left.minX;
b.minY = up.minY;
if (leftUp == null) {
b.list.add(Point.init(left.minX, j));
b.list.add(Point.init(i, up.minY));
} else {
int minY = up.minY;
for (Point llp : left.list) {
if (minY <= llp.y) {
b.list.add(llp);
} else {
b.list.add(Point.init(llp.x, minY));
break;
}
}
if (up.minY < left.minY)
b.list.add(Point.init(i, minY));
}
return b;
}
public int calSize(int i, int j) {
int max = 0;
for (Point point : list) {
max = Math.max(point.calSize(i, j), max);
}
return max;
}
}
static class Point {
int x;
int y;
public static Point init(int x, int y) {
Point p = new Point();
p.x = x;
p.y = y;
return p;
}
public int calSize(int a, int b) {
return (a - x + 1) * (b - y + 1);
}
}
}