题目: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);