CCI: Find maximum subsquare

Imagine you have a square matrix, where each cell is filled with either black or white. Design an algorithm to find the maximum subsquare such that all four borders are filled with black pixels.

用0表示black, 1表示white。O(N^4)的解法显而易见,直接brute force遍历 - 按照尺寸从大到小,每行,每列依次判断是否为正方形。判断正方形需要检查四条边,所以也是O(n)。这里加一个预处理,把判断是否为正方形降到O(1),整体降到O(N^3)。核心思想是记录下每个位置下面和右边有几个0,这样可以找到正方形的三个顶点来判断0的个数。

struct Square {
	int x;
	int y;
	int size;

	Square() : x(0), y(0), size(0) { }
	Square(int row, int col, int sz) : x(row), y(col), size(sz) { }
};

struct Cell {
	int zeros_right;
	int zeros_below;

	Cell() : zeros_right(0), zeros_below(0) { }
	Cell(int rzeros, int bzeros) : zeros_right(rzeros), zeros_below(bzeros) { }
};

void CCIMatrix::getMaxSubSquareTest() {
	CCIMatrix cci_matrix;
	int size = 6;
	int array2d[][6] = {
		{1, 0, 0, 0, 1, 1},
		{0, 0, 1, 1, 1, 0},
		{1, 0, 0, 0, 0, 1},
		{1, 1, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 1},
		{0, 0, 0, 0, 1, 0}
	};

	vector<vector<int>> matrix(size, vector<int>(size));
	for (int i = 0; i < size; ++i) {
		matrix[i] = vector<int>(array2d[i], array2d[i] + size);
	}

	Square subsquare = cci_matrix.getMaxSubSquare(matrix);
	cout << "The max subsquare with balck is: (" << subsquare.x << ", " << subsquare.y << ") with size " << subsquare.size;
}

Square CCIMatrix::getMaxSubSquare(const vector<vector<int>> &matrix) {
	Square max_square;
	vector<vector<Cell>> processed = processMaxSubSquare(matrix);
	for (int size = matrix.size(); size > 0; --size) {
		max_square = getSubSquareWithSize(processed, size);
		if (max_square.size > 0) {
			break;
		}
	}

	return max_square;
}

Square CCIMatrix::getSubSquareWithSize(const vector<vector<Cell>> &processed, int size) {
	int bound = processed.size();
	for (int i = 0; i <= bound - size; ++i) {
		for (int j = 0; j <= bound - size; ++j) {
			if (isSquare(processed, i, j, size)) {
				return Square(i, j, size);
			}
		}
	}

	return Square();
}

bool CCIMatrix::isSquare(const vector<vector<Cell>> &processed, int row, int col, int size) {
	if (processed[row][col].zeros_below < size || processed[row][col].zeros_right < size) {
		return false;
	}
	if (processed[row][col+size-1].zeros_below < size) {
		return false;
	}
	if (processed[row+size-1][col].zeros_right < size) {
		return false;
	}

	return true;
}

vector<vector<Cell>> CCIMatrix::processMaxSubSquare(const vector<vector<int>> &matrix) {
	int size = matrix.size();
	vector<vector<Cell>> processed(size, vector<Cell>(size));
	for (int i = size - 1; i >= 0; --i) {
		for (int j = size - 1; j >= 0; --j) {
			// Only handle the black element
			if (matrix[i][j] == 0) {
				int zeros_right = 1;
				int zeros_below = 1;
				if (j + 1 < size) {
					zeros_right += processed[i][j+1].zeros_right;
				}
				if (i + 1 < size) {
					zeros_below += processed[i+1][j].zeros_below;
				}
				processed[i][j].zeros_right = zeros_right;
				processed[i][j].zeros_below = zeros_below;
			}
		}
	}

	return processed;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值