单调栈的应用——求最大子矩阵的大小

题目:
给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的所有矩形区域中, 最大的矩形区域为1的数量。
示例1:

输入:
1 1 1 0
输出:
3

示例2:

输入:
1 0 1 1
1 1 1 1
1 1 1 0
输出:
6

解题思路:
这个题是单调栈的应用。那么什么是单调栈呢?
单调栈分为单调递增栈和单调递减栈,通过使用单调栈我们可以访问到下一个和上一个 比他大(小)的元素。也就是说在队列或数组中,我们需要通过比较前后元素的大小关系来解决问题时我们通常使用单调栈。
下面这个问题我们就可以用单调栈解决。参考博客
在这里插入图片描述
我们可以想象每个直方图里面有一个和直方图高度一样的竹竿,我们拿着竹竿向右移动,遇到比竹竿短的我们会卡住。这时这个直方图的最大面积就是它自己。如果竹竿可以移动,那么最大面积就是竹竿移动的距离和竹竿的高度相乘。
具体代码如下:

import java.util.Stack;

public class 求最大子矩阵的大小 {

	public static int maxRecSize(int[][] map) {
		if (map == null || map.length == 0 || map[0].length == 0) {
			return 0;
		}
		int l = map[0].length;
		int[] height = new int[l];
		int maxArea = 0;
		//从第一行开始计算最大直方图的面积并依次相加
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < l; j++) {
				height[j] = map[i][j] == 0 ? 0 : height[j] + 1;
			}
			maxArea = Math.max(maxRecFromBottom(height), maxArea);
		}
		return maxArea;
	}

	// 给定一个数组,算出这个矩阵的直方图最大的矩形面积
	public static int maxRecFromBottom(int[] height) {
		if (height.length == 0 || height == null)
			return 0;
		int maxArea = 0;
		int len = height.length;
		Stack<Integer> stack = new Stack<Integer>();
		for (int i = 0; i < len; i++) {
			//如果栈不为空,竹竿遇到比自己小的直方图
			while (!stack.isEmpty() && height[i] <= height[stack.peek()]) {
				int j = stack.pop();//竹竿弹出
				int k = stack.isEmpty() ? -1 : stack.peek();//竹竿移动的左边界
				int curArea = (i - k - 1) * height[j];//竹竿移动的面积
				maxArea = Math.max(curArea, maxArea);
			}
			stack.push(i);
		}
		//当遍历完数组之后,栈中还有元素时,竹竿的右边界为数组的长度
		while (!stack.isEmpty()) {
			int j = stack.pop();
			int k = stack.isEmpty() ? -1 : stack.peek();//竹竿移动的左边界
			int curArea = (len - k - 1) * height[j];
			maxArea = Math.max(curArea, maxArea);
		}
		return maxArea;

	}
	//测试
	public static void main(String[] args) {
//		int[][] map = { { 1, 1, 1, 0 } };
		int[][] map = { { 1, 1, 0, 1 }, { 1, 1, 1, 1 },{ 1, 1, 1, 0 }};
		int res = maxRecSize(map);
		System.out.println(res);
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值