程序员面试金典——最大子方阵问题:找到四条边颜色相同的最大子方阵

问题描述:

有一个方阵,其中每个单元(像素)非黑即白(非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;
		}
	}
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值