版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luke2834/article/details/79338681
题意
- 给定一个0,1矩阵,希望找到矩阵中的一个面积最大的联通正方形区域,这个区域中全是1
思路
- 基本思路:找面积最大的,其实就是找最长的边长,我们的思路都是以这个为出发点的
dp思路
- 整体来看,就是一个二维dp,是这类矩阵问题的一个常用状态设置方法: 的含义是以 为右下角的最大正方形边长
- 然后递推方程,我们一定是看 、 以及 了
- 通过观察矩阵形状,我们不难发现当
时,小的那个正方形决定了
为右下角这个正方形的边长,这时
- 而当
时,左上角的位置是否为0决定了当前正方形的边长,这时可以用个小trick,不用真去看左上角为
还是
,可以通过
去判断一下(这个小trick意义不大,就是递推形式上更像dp,2333),即
单调队列思路
- 这个问题我们可以把行列分开来看
- 我们先对每一行单独来看,计算第 个元素前有多少个连续的 ,存下来
- 再对每一列单独去看,我们的任务就变成在一个一维数组中,找到最长连续子段,这个子段上元素的最小值要大于等于子段的长度
- 这个很类似于滑动窗口最大值之类的问题,比较容易想到用一个单调队列就可以了,具体操作可以参考实现
实现
- 单调队列实现
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.size() == 0)
return 0;
int n = matrix.size(), m = matrix[0].size();
vector<vector<int>> a(n, vector<int>(m, 0));
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (matrix[i][j] == '0'){
a[i][j] = 0;
}
else{
if (j == 0){
a[i][j] = 1;
}
else{
a[i][j] += a[i][j - 1] + 1;
}
}
}
}
int ans = 0;
for (int j = 0; j < m; j++){
deque<pair<int, int> > q;
int len = 1;
for (int i = 0; i < n; i++){
while (q.size() && q.back().first > a[i][j]){
q.pop_back();
}
q.push_back(make_pair(a[i][j], i));
if (q.front().first < len){
len = i - q.front().second + 1;
q.pop_front();
}
else {
ans = max(ans, len);
len++;
}
}
}
return ans * ans;
}
};
- dp实现
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.size() == 0)
return 0;
int n = matrix.size(), m = matrix[0].size();
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
int ans = 0;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (matrix[i-1][j-1] == '0'){
continue;
}
if (dp[i-1][j] == dp[i][j-1]){
dp[i][j] = dp[i-1][j];
if (dp[i-1][j-1] >= dp[i-1][j]){
dp[i][j]++;
}
}
else{
dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1;
}
ans = max(ans, dp[i][j]);
}
}
return ans * ans;
}
};