- 这题,最开始想用搜索/暴力做,尝试过后,感觉实在麻烦。这题,关键还是要看出最优子结构,从而使用动态规划。
- 每个为1的小方块,要想和大方块合并成为一个更大的方块,只能从 以左上、上方、左边的小方块为右下角的大方块那转移过来,而且只能从这四个里面选一个最小的,不然的话,无法保证其他两个边都有。
- 定义状态:dp[i][j] 以 matrix[i][j] 为右下角的正方形的最大边长。(定义成面积虽然更直观,但是转移的时候很麻烦,要开更号求边长)
- 递推方程:
dp(i,j) = min{dp(i-1,j),dp(i-1,j-1),dp(i,j-1)} + 1
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if(!matrix.size()) return 0;
int n = matrix.size(),m = matrix[0].size();
if(n == 0 || m == 0) return 0;
int dp[n + 1][m + 1];
memset(dp,0,sizeof(dp));
int maxside = 0;
for(int r = 0;r < n;++r){
for(int c = 0;c < m;++c){
if(matrix[r][c] == '1')
dp[r+1][c+1] = min(dp[r][c],min(dp[r+1][c],dp[r][c+1])) + 1;
maxside = max(maxside,dp[r+1][c+1]);
}
}
return pow(maxside,2);
}
};
这题,和上面差不多,只不过统计答案的时候,要转变下思路。
class Solution {
public:
int countSquares(vector<vector<int>>& matrix) {
if(matrix.empty()) return 0;
int n = matrix.size(), m = matrix[0].size();
if(!n || !m) return 0;
int dp[n + 1][m + 1];
memset(dp,0,sizeof(dp));
int sum = 0;
for(int r = 0;r < n;++r){
for(int c = 0;c < m;++c){
if(matrix[r][c] == 1){
dp[r + 1][c + 1] = min(dp[r][c],min(dp[r + 1][c],dp[r][c + 1])) + 1;
sum += dp[r + 1][c + 1];
}
}
}
return sum;
}
};