[CTCI] 最大子方阵
题目描述
有一个方阵,其中每个单元(像素)非黑即白(非0即1),请设计一个高效算法,找到四条边颜色相同的最大子方阵。
给定一个01方阵mat,同时给定方阵的边长n,请返回最大子方阵的边长。保证方阵变长小于等于100。
测试样例:
[[1,1,1],[1,0,1],[1,1,1]],3
返回:3
要看清题目,题目说的是四条边同一种颜色,不是四条边都是1。想法就是记录每个点右侧与下侧的连续0或1的个数,这样在给定一个左上角坐标与边长时,可以以O(1)的时间判断是否构成矩形。总的时候复杂度为O(N^3)。
1 class SubMatrix { 2 public: 3 struct cell { 4 int right, down; 5 cell() : right(0), down(0){} 6 }; 7 int maxSubMatrix(vector<vector<int> > mat, int n) { 8 // write code here 9 vector<vector<cell>> mmat1(n, vector<cell>(n)); 10 vector<vector<cell>> mmat2(n, vector<cell>(n)); 11 int tmp1, tmp2, res; 12 for (int i = n - 1; i >= 0; --i) { 13 for (int j = n - 1; j >= 0; --j) { 14 if (j == n - 1) tmp1 = tmp2 = 0; 15 else tmp1 = mmat1[i][j+1].right, tmp2 = mmat2[i][j+1].right; 16 if (mat[i][j] == 1) mmat1[i][j].right = tmp1 + 1; 17 else mmat2[i][j].right = tmp2 + 1; 18 if (i == n - 1) tmp1 = tmp2 = 0; 19 else tmp1 = mmat1[i+1][j].down, tmp2 = mmat2[i+1][j].down; 20 if (mat[i][j] == 1) mmat1[i][j].down = tmp1 + 1; 21 else mmat2[i][j].down = tmp2 + 1; 22 } 23 } 24 for (int i = n; i > 0; --i) { 25 if (isOK(mmat1, n, i) || isOK(mmat2, n, i)) return i; 26 } 27 return 0; 28 } 29 bool isOK(vector<vector<cell>> &mat, int n, int size) { 30 for (int i = 0; i <= n - size; ++i) { 31 for (int j = 0; j <= n - size; ++j) { 32 if (isSquare(mat, i, j, size)) return true; 33 } 34 } 35 return false; 36 } 37 bool isSquare(vector<vector<cell>> &mat, int x, int y, int size) { 38 cell &lefttop = mat[x][y], &leftdown = mat[x+size-1][y], &righttop = mat[x][y+size-1]; 39 if (lefttop.right < size) return false; 40 if (lefttop.down < size) return false; 41 if (leftdown.right < size) return false; 42 if (righttop.down < size) return false; 43 return true; 44 } 45 };