问题描述:
有一个方阵,其中每个单元(像素)非黑即白(非0即1),请设计一个高效算法,找到四条边颜色相同的最大子方阵。
给定一个01方阵mat,同时给定方阵的边长n,请返回最大子方阵的边长。保证方阵边长小于等于100。
测试样例:
[[1,1,1],[1,0,1],[1,1,1]],3
返回:3解决思路:
采用动态规划思想,用两个辅助数组left和up,left[i][j]表示连续紧挨着mat[i][j]的左边有多少个与mat[i][j]相同的元素数,如果没有则为1,即只有自己相等。同理up[i][j]表示连续紧挨着mat[i][j]的上边有多少个与mat[i][j]相同的元素数,如果没有则为1。
然后依次判断数组的元素左边和右边元素与其相等,这个元素有可能是满足条件的正方形的右下角顶点,然后进行详细的判断。
class SubMatrix {
public:
int maxSubMatrix(vector<vector<int> > mat, int n) {
//采用动态规划思想,用两个辅助数组left和up,left[i][j]表示连续紧挨着mat[i][j]的左边有多少个与mat[i][j]相同的元素数,如果没有则为1,即只有自己相等。
//同理up[i][j]表示连续紧挨着mat[i][j]的上边有多少个与mat[i][j]相同的元素数,如果没有则为1。
int maxlen = 1;
vector <vector<int>> left(n),up(n);
for (int i = 0; i < n; ++i)
{
left[i].resize(n);
up[i].resize(n);
}
initial(mat, left, up, n);
for (int i = 1; i < n; ++i)
{
for (int j = 1; j < n; ++j)
{
if (mat[i][j] == mat[i][j - 1] && mat[i][j] == mat[i - 1][j])//该元素左边和右边元素与其相等,这个元素有可能是满足条件的正方形的右下角顶点
{
left[i][j] = left[i][j - 1] + 1;
up[i][j] = up[i - 1][j] + 1;
int len = left[i][j] < up[i][j] ? left[i][j] : up[i][j];
for (int k = len - 1; k > 0 && k + 1 > maxlen; --k)
{
//此处计算maxlen,依次判断以mat[i][j]为右下顶点的正方形边长依次为len到maxlen+1是否可行,可行则更新maxlen,不用再减1计算了,否则保持不变。
if (left[i - k][j] > k&&up[i][j - k] > k)
{
maxlen = k + 1;
break;
}
}
}
else
{
if (mat[i][j] == mat[i][j - 1])
left[i][j] = left[i][j - 1] + 1;
else
left[i][j] = 1;
if (mat[i][j] == mat[i - 1][j])
up[i][j] = up[i - 1][j] + 1;
else
up[i][j] = 1;
}
}
}
return maxlen;
}
private:
void initial(vector<vector<int> > &mat, vector<vector<int> > &left, vector<vector<int> > &up, int n)
{
for (int i = 0; i < n; ++i)
{
left[i][0] = 1;
up[0][i] = 1;
}
for (int i = 1; i < n; ++i)
{
if (mat[0][i] == mat[0][i - 1])
left[0][i] = left[0][i - 1] + 1;
else
left[0][i] = 1;
if (mat[i][0] == mat[i - 1][0])
up[i][0] = up[i - 1][0] + 1;
else
up[i][0] = 1;
}
}
};