009-求最大子矩阵的大小

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;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值