给定整形矩阵map,计算最大矩形区域为1的数量

给定整形矩阵map,计算最大矩形区域为1的数量

如题:

思路:

此处需要用到单调栈

1.首先对每一行进行遍历,并构造以当前行作为底部,的一个直方图。

举个例子,假设数据如下:

3 4                 
1 0 1 1    
1 0 1 0             
1 1 1 1            

那么先遍历第一行,得到的直方图就是   1 0 1 1,  然后我们计算最大的包含1的矩形区域

然后比那里第二行,这次以第二行作为底部,进行直方图的构建, 2  0  2  0  ,即从第2行往上,如果接壤,就继续+1,否则从0 开始

第三行就是   3 1  3  1

2.然后对于每一行所的得到的直方图,用单调栈进行计算这个包含最大的矩形面积。

因为某一行如果出现了不接壤,所以很可能会断掉,所以要对每一行的直方图进行计算。

如何计算呢?

可以利用单调栈,对每一个直方图的点histogram[i] 进行寻找

1).距离 histogram[i]最近的右边 且 histogram[i]的值 的 下标

2).距离 histogram[i]最近的左边 且 histogram[i]的值 的 下标

3).然后根据 histogram[i]的高度,进行面积的计算,最后取最大即可

代码:

#include<iostream>
#include<cstdlib>
#include<stack>
#include<cstring>
using namespace std;

int map_[1000][1000];
int histogram[1000];
//利用单调栈进行计算 
int cal_max(int arr[],int len){
	stack<int> stk;
	int max_ = 0;
	//对每一个值进行以单调栈的计算方式 栈顶至栈底为从大到小的形式 
	for(int j=0;j<len;j++){
		// 如果碰到 当前遍历的值,大于栈顶,则直接压栈
		// 反之 则把当前栈顶的值弹出来进行计算 
		while(!stk.empty() && arr[stk.top()]>=arr[j]){
			int right_min = j; // 距离栈顶最近的右边 且 比栈顶小的值 的 下标 
			int high = arr[stk.top()]; stk.pop();  // 当前栈顶的  高度 
			int left_min = stk.empty()? -1 : stk.top();  //距离栈顶最近的左边 且 比栈顶小的值 的 下标
			max_ = max(max_,high*(right_min - left_min-1)); 
		}
		stk.push(j);
	}
	//最后要处理未弹出完毕的值
	//因为此时一定是栈顶至栈底是从大到小
	//所以如果栈中还 存在值, 说明当前一定包含最后一个数
	//所以右边  距离栈顶最近的右边 且 比栈顶小的值 的 下标 不存在 
	int right_min =len;
	while(!stk.empty()){
		int high = arr[stk.top()]; stk.pop();
		int left_min = stk.empty()? -1 : stk.top();
		max_ = max(max_,high*(right_min - left_min-1));
	}
	return max_; 
}

/*
3 4          对应直方图 
1 0 1 1     ==》 1 0 1 1
1 0 1 0          2 0 2 0
1 1 1 1          3 1 3 1
*/
int main(){
	
	int M,N;// map  的 高 和宽 
	scanf("%d %d",&M,&N);
	for(int i=0;i<M;i++){
		for(int j=0;j<N;j++){
			scanf("%d",&map_[i][j]);
		}
	}
	//设计一个统计直方图 
	memset(histogram,0,N*sizeof(int));
	int max_ = 0;
	for(int i=0;i<M;i++){
		for(int j=0;j<N;j++){
			//从第i行为底 进行直方图的统计, 即如果不黏连,则为0,否则,加上之前的统计 
			histogram[j] = map_[i][j] == 0 ? 0:histogram[j]+1;
		}
		//对这个直方图进行计算 求最大值 
		int temp = cal_max(histogram,N);
		max_ = max(max_,temp);
	}
	printf("%d\n",max_);
	return 0;
}

3.注意

1.单调栈必须要确保序列不重复的情况,本题虽然存在重复情况,但是最后一个重复值依然能够计算出正确答案。

2.这里单调栈存的是下标,但是决策依然是已经直方图的“值”来进行决策的。

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值