|
|
package class25;
|
|
|
|
|
|
// 测试链接:https://leetcode.com/problems/count-submatrices-with-all-ones
|
|
|
public class Code05_CountSubmatricesWithAllOnes {
|
|
|
|
|
|
public static int numSubmat(int[][] mat) {
|
|
|
if (mat == null || mat.length == 0 || mat[0].length == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
int nums = 0;
|
|
|
int[] height = new int[mat[0].length];
|
|
|
for (int i = 0; i < mat.length; i++) {
|
|
|
for (int j = 0; j < mat[0].length; j++) {
|
|
|
height[j] = mat[i][j] == 0 ? 0 : height[j] + 1;
|
|
|
}
|
|
|
nums += countFromBottom(height);
|
|
|
}
|
|
|
return nums;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 比如
|
|
|
// 1
|
|
|
// 1
|
|
|
// 1 1
|
|
|
// 1 1 1
|
|
|
// 1 1 1
|
|
|
// 1 1 1
|
|
|
//
|
|
|
// 2 .... 6 .... 9
|
|
|
// 如上图,假设在6位置,1的高度为6
|
|
|
// 在6位置的左边,离6位置最近、且小于高度6的位置是2,2位置的高度是3
|
|
|
// 在6位置的右边,离6位置最近、且小于高度6的位置是9,9位置的高度是4
|
|
|
// 此时我们求什么?
|
|
|
// 1) 求在3~8范围上,必须以高度6作为高的矩形,有几个?
|
|
|
// 2) 求在3~8范围上,必须以高度5作为高的矩形,有几个?
|
|
|
// 也就是说,<=4的高度,一律不求
|
|
|
// 那么,1) 求必须以位置6的高度6作为高的矩形,有几个?
|
|
|
// 3..3 3..4 3..5 3..6 3..7 3..8
|
|
|
// 4..4 4..5 4..6 4..7 4..8
|
|
|
// 5..5 5..6 5..7 5..8
|
|
|
// 6..6 6..7 6..8
|
|
|
// 7..7 7..8
|
|
|
// 8..8
|
|
|
// 这么多!= 21 = (9 - 2 - 1) * (9 - 2) / 2
|
|
|
// 这就是任何一个数字从栈里弹出的时候,计算矩形数量的方式
|
|
|
public static int countFromBottom(int[] height) {
|
|
|
if (height == null || height.length == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
int nums = 0;
|
|
|
int[] stack = new int[height.length];
|
|
|
int si = -1;
|
|
|
for (int i = 0; i < height.length; i++) {
|
|
|
while (si != -1 && height[stack[si]] >= height[i]) {
|
|
|
int cur = stack[si--];
|
|
|
if (height[cur] > height[i]) {
|
|
|
int left = si == -1 ? -1 : stack[si];
|
|
|
int n = i - left - 1;
|
|
|
int down = Math.max(left == -1 ? 0 : height[left], height[i]);
|
|
|
nums += (height[cur] - down) * num(n);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
stack[++si] = i;
|
|
|
}
|
|
|
while (si != -1) {
|
|
|
int cur = stack[si--];
|
|
|
int left = si == -1 ? -1 : stack[si];
|
|
|
int n = height.length - left - 1;
|
|
|
int down = left == -1 ? 0 : height[left];
|
|
|
nums += (height[cur] - down) * num(n);
|
|
|
}
|
|
|
return nums;
|
|
|
}
|
|
|
|
|
|
public static int num(int n) {
|
|
|
return ((n * (1 + n)) >> 1);
|
|
|
}
|
|
|
|
|
|
}
|