题目:题目链接
思路:让你找全是一的最大的全为’1’的正方形面积。
方法一 暴力
最先想到的,那必然是暴力。我们先找一个点,然后把这个点当作正方形的左上角,在遍历正方形的最大边长。
注意:我们只需要遍历新加的一行和一列就可以了哦!
看代码吧:
class Solution {
public:
int n, m;
void findSquare(int i, int j, int& max_len, vector<vector<char>>& matrix) {
if (m - i <= max_len || n - j <= max_len) return;
int square_len = 1;
bool f = true;
while (i + square_len < m && j + square_len < n) {
for (int k = 0; k <= square_len; ++k) {//看看i+square_len,我们每次只遍历新加的一行和一列。
if (matrix[i + k][j + square_len] != '1' || matrix[i + square_len][j + k] != '1') {//如果该边长的正方形内有不是0的。
f = false;
break;
}
}
if (f) square_len++;
else break;
}
max_len = max(max_len, square_len);
return;
}
int maximalSquare(vector<vector<char>>& matrix) {
m = matrix.size();
n = matrix[0].size();
int max_len = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == '1') {
findSquare(i, j, max_len, matrix);
}
}
}
return max_len * max_len;//记住是求面积!
}
};
方法二 动态规划
这就离谱了啊,我看半天官方的dp也没看懂。我讲一讲我的理解吧。首先dp[i][j]是以(i,j)为右下角的最大正方形。
那么显然有状态转移方程:
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
dp[i][j] = min(dp[i-1][j],dp[i-1][j],dp[i][j-1]
dp[i][j]=min(dp[i−1][j],dp[i−1][j],dp[i][j−1]
不显然是嘛,没事我也不懂这个,听我慢慢道来:
先来看一张图:
bdq,微软自带画图。
我们来看看,这是三个正方形哈,虽然有点不正。那么对于以(i,j)为右下角的最大正方形,其(i,j)左边的边长(也就是正方形下面的边)是不是一定是min(a,b)+1,对不对,想想看。那么(i,j)上面的边长(也就是正方形的右边竖着的边)是不是一定是min(a,c)+1。那么正方形的边最长是不是一定是min(min(a,b),min(a,c))+1,也就是min(a,b,c)+1。而且a,b,c分别对应dp[i-1][j],dp[i,j-1],dp[i-1][j-1]。
兄弟们,我讲的不是很清楚,你再看看上面那个丑图!!!看看有没有收获。
如果懂了状态转移方程,那么代码就很快了:
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<vector<int> > dp(m, vector<int>(n));
int max_len = 0;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == '1') {
if (i == 0 | j == 0) dp[i][j] = 1;
else dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
max_len = max(max_len, dp[i][j]);
}
}
return max_len * max_len;
}
};
想看严格证明,请看标准证明该状态转移方程。
加油兄弟!!!!!加油加油加油加油加油!!!!!!