【难】【DP】计算bool矩阵中,仅包含1的最大矩形和最大正方形

题目:EPI


class record
{
public:
	int right;//如果一个点是1,则记录该点右边有多少个连续的1(包括该点本身)
	int down;//如果一个点是1,则记录该点下边有多少个连续的1(包括该点本身)
	record(){}
	record(int r,int d):right(r),down(d){}
};

//计算最大矩形区域
int find_largest_rectangle(const vector<vector<bool>> &A)
{
	if(A.empty() || A[0].empty())
		return -1;
	int rows=A.size(),cols=A[0].size();
	vector<vector<record>> m(rows,vector<record>(cols));
	for(int i=rows-1;i>=0;i--)
	{
		for(int j=cols-1;j>=0;j--)
		{
			if(A[i][j])
			{
				int r=j==cols-1?1:m[i][j+1].right+1;
				int d=i==rows-1?1:m[i+1][j].down+1;
				m[i][j]=record(r,d);
			}
			else
				m[i][j]=record(0,0);
		}
	}
	int res=0;
	for(int i=rows-1;i>=0;i--)
	{
		for(int j=cols-1;j>=0;j--)
		{
			if(A[i][j] && m[i][j].down*m[i][j].right>res)
			{
				int min_r=m[i][j].right;
				for(int k=0;k<m[i][j].down;k++)
				{
					min_r=min(min_r,m[i+k][j].right);
					int tmp=(k+1)*min_r;
					res=max(res,tmp);
				}
			}
		}

	}
	return res;
}

//计算最大正方形区域
int find_largest_square(const vector<vector<bool>> &A)
{
	if(A.empty() || A[0].empty())
		return -1;
	int rows=A.size(),cols=A[0].size();
	vector<vector<record>> m(rows,vector<record>(cols));
	for(int i=rows-1;i>=0;i--)
	{
		for(int j=cols-1;j>=0;j--)
		{
			if(A[i][j])
			{
				int r=j==cols-1?1:m[i][j+1].right+1;
				int d=i==rows-1?1:m[i+1][j].down+1;
				m[i][j]=record(r,d);
			}
			else
				m[i][j]=record(0,0);
		}
	}
	int res=0;
	//side记录一个点作为正方形的左上角时,所能获得的最大边长的正方形
	vector<vector<int>> side(rows,vector<int>(cols,0));
	for(int i=rows-1;i>=0;i--)
	{
		for(int j=cols-1;j>=0;j--)
		{
			if(A[i][j])
			{
				int s=min(m[i][j].right,m[i][j].down);
				if(i<rows-1 && j<cols-1)
					s=min(s,side[i+1][j+1]+1);
				side[i][j]=s;
				res=max(res,s*s);
			}
		}

	}
	return res;
}

相关题型:《程序员面试金典》P345

给定一个bool类型的方阵,设计一个算法,找出四条边皆为1的最大子方阵。

class record
{
public:
	int right;//如果一个点是1,则记录该点右边有多少个连续的1(包括该点本身)
	int down;//如果一个点是1,则记录该点下边有多少个连续的1(包括该点本身)
	record(){}
	record(int r,int d):right(r),down(d){}
};

//矩阵中以点A[row][col]为左上角、边长为side的正方形
class square
{
public:
	int row,col;
	int side;
	square(int r,int c,int s):row(r),col(c),side(s){}
};

bool Issquare(const vector<vector<bool>> &A,const vector<vector<record>> &m,const int row,const int col,const int side)
{
	if(m[row+side-1][col].right<side)
		return false;
	if(m[row][col+side-1].down<side)
		return false;

	return true;
}

square find_largest_square_one_encircle(const vector<vector<bool>> &A)
{
	square res(-1,-1,-1);
	if(A.empty() || A.size()!=A[0].size())
		return res;
	int n=A.size();
	vector<vector<record>> m(n,vector<record>(n));
	for(int i=n-1;i>=0;i--)
	{
		for(int j=n-1;j>=0;j--)
		{
			if(A[i][j])
			{
				int r=j==n-1?1:m[i][j+1].right+1;
				int d=i==n-1?1:m[i+1][j].down+1;
				m[i][j]=record(r,d);
			}
			else
				m[i][j]=record(0,0);
		}
	}

	for(int i=n-1;i>=0;i--)
	{
		for(int j=n-1;j>=0;j--)
		{
			if(A[i][j])
			{
				int side=min(m[i][j].right,m[i][j].down);
				if(side<=res.side)
					continue;
				while(side>res.side)
				{
					if(Issquare(A,m,i,j,side))
					{
						res.row=i;
						res.col=j;
						res.side=side;
						break;
					}
					else
						side--;
				}
			}
		}
	}
	return res;
}

测试代码:

bool a[4][4]={{0,0,1,0},{0,1,1,1},{1,1,1,1},{0,1,1,1}};
	vector<vector<bool>> A(4,vector<bool>(4));
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++)
			A[i][j]=a[i][j];
	cout<<find_largest_rectangle(A);




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值