题目

思路
本道题有点类似寻找最大矩形,不过那题运用的是栈,这道题运用动态规划相对来说比较简单,那么这道题的思路是什么呢?
先说说我一开始的思路:我设想是设置一个dp表,表示某个值为1的点作为正方形右下角时最大的矩形面积,但是这种想法最后证实不怎么好进行推进,也就是说比较难得出动态规划方程。后来我就想设置两个dp表,一个表示以该点为终点时高的最大值,一个表示以该点为终点时底边的最大值,然后在二者之间选择值小的那一个作为正方形的边,但最后证实这种思路也是错误的

如上图,对于这种情况会返回一个错误的结果,因为我们只关注了两条边(一条高,一条边),但是不能保证其他边上都是由1构成
参考了其他人的思路,我们可以设置一个二维的dp表(因为我们发现一维的dp表处理二维矩阵起来不怎么能够表示),其中dp[i][j]表示以该点作为正方形的右下角所能构成的最大边长(因为如果将dp表表示为面积的话,不好得出状态转移方程,相反如果将dp表表示为边长的话,那么边与边之间相差只是一个常量),对于某个值为‘1’的点作为右下角,那么他能构成的最大正方形的边长为多少呢,我们先看下面一个例子:

对于两条线段的交点(我们暂且称它为点i)来说,那么这两条线段(注意前提条件是线段上都是由1构成的),那么目前这两条线段所能组成的最大正方形的边长肯定是以短的一条作为边长,所以目前由点i所能构成的最大正方形的边长就为2
但是到了这一步还不行,上面我就是只考虑了这一种情况,下面这个就是反例:

我们可以看到,,只考虑上左两个方向是不够的,我们还需要考虑左上方的方向,因为对于一个正方形的右下角的点来说,它的左上方方向的点作为一个右下角也必然能构成一个正方形,此时两个正方形的边长关系就是相差1
所以状态转移方程就为:dp[i][j]=1+min(dp[i-1][j],dp[i][j01],dp[i-1][j-1]),dp[i-1][j]表示的是正上方方向,dp[i][j-1]表示的是正左方方向,dp[i-1][j-1]表示的是左上方方向。
相关代码如下:
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.empty() || matrix[0].empty())
return 0;
int m = matrix.size();
int n = matrix[0].size();
vector<vector<int>> dp(m, vector<int>(n,0));
int Max = 0;
for (int i = 0; i < n; i++) {
if (matrix[0][i] == '1') {
dp[0][i] = 1;
Max = 1;
}
}
for (int i = 1; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '1') {
if (j == 0) {
dp[i][j] = 1;
}
else
dp[i][j] = 1 + min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
}
else dp[i][j] = 0;
Max = max(Max, dp[i][j]);
}
}
return Max * Max;
}
};
1379

被折叠的 条评论
为什么被折叠?



