package com.my.suanfa;
import java.util.Stack;
/**
*如果矩阵大小为O(N * M),那么时间复杂度为O(N * M)
* 求最大子矩阵的大小
* 关键有两个步骤:
* 步骤1:以每一行做切割,使用高度数组height,来记录以当前行为底,每个位置往上的连续1的个数
* 步骤2:每切割一行,统计以该行切割所获得的最大子矩阵中1的个数
* */
public class Solution05 {
/**
* 以每一行切割
* */
public int maxRecSize(int[][] map) {
//边界条件判断
if(map == null || map.length == 0 || map[0].length == 0) {
return 0;
}
//创建高度数组
int[] height = new int[map[0].length];
int maxArea = 0;
//遍历二维数组进行切割统计
for(int i = 0; i < map.length; i++) {
for(int j = 0; j < map[0].length; j++) {
height[j] = map[i][j] == 0 ? 0 : height[j] + 1;
}
maxArea = Math.max(maxArea, maxRecFromBottom(height));
}
return maxArea;
}
/**
* 统计最大子矩阵中1的个数
* */
public int maxRecFromBottom(int[] height) {
//边界条件判断
if(height == null || height.length == 0) {
return 0;
}
int maxArea = 0;
//创建一个栈数据结构来帮助完成统计,栈中存储的是进栈元素的下标
Stack<Integer> stack = new Stack<Integer>();
//栈中元素从栈顶到栈底依次减小,如果此时栈不为空,并且当前要进栈的元素小于此刻栈顶的元素,那么栈顶元素出栈,并统计出栈元素向左,向右所能扩展的最大矩阵,并统计
for(int i = 0; i < height.length; i++) {
while(!stack.isEmpty() && height[i] <= height[stack.peek()]) {
//j记录的是出栈的元素
int j = stack.pop();
//k记录的是当前栈顶的元素
int k = stack.isEmpty() ? -1 : stack.peek();
//因为出栈的元素对应的下表为j,所以height[j]
//因为栈中的下标所对应的元素从栈顶到栈底是依次递减的,所以出栈下标j向左最多能扩展到k + 1,向右最多能扩展到i - 1,因此矩形的宽度为((i - 1) - (k + 1) + 1),高度为height[j]
int curArea = ((i - 1) - (k + 1) + 1) * height[j];
maxArea = Math.max(maxArea, curArea);
}
stack.push(i);
}
//以上只是统计了出栈元素,而栈内元素还没有统计,这时i == height.length,超出了循环的范围,无法继续循环
while(!stack.isEmpty()) {
//j记录的是出栈元素
int j = stack.pop();
//i 记录的是下一个要进栈的元素,因为元素已经全部进栈,所以下一个要建栈的元素的下标始终为height.length,值为无穷小,小于栈中任意元素,所以不断从栈中弹出元素并统计,直到栈为空,则统计完毕
int i = height.length;
//k记录当前栈顶元素
int k = stack.isEmpty() ? -1 : stack.peek();
//因为出栈的元素对应的下表为j,所以height[j]
//因为栈中的下标所对应的元素从栈顶到栈底是依次递减的,所以出栈下标j向左最多能扩展到k + 1,向右最多能扩展到i - 1,因此矩形的宽度为((i - 1) - (k + 1) + 1),高度为height[j]
int curArea = ((i - 1) - (k + 1) + 1) * height[j];
maxArea = Math.max(maxArea, curArea);
}
return maxArea;
}
}
009-求最大子矩阵的大小
最新推荐文章于 2022-09-03 21:58:19 发布