题目:最大正方形. - 力扣(LeetCode)
题解:
第一种方法:前缀和+二分答案(暴力优化) 我感觉比官方给的暴力好一点
时间复杂度:
- 暴力优化1: 通过前缀和减少判断1出现得次数**(这个题比较特别,只有0,1)**
- **暴力优化2:**答案单调,二分答案
在check函数中,我去找了当答案为x时,即找到所有x * x得正方形来进行判断,如果它得值为x * x,那么说明答案成立。
代码1
cpp
class Solution {
public:
bool check(int x, int n, int m, const vector<vector<int>>& sum)
{
if(x == 0) return true;
int ans = x * x;
for(int i = x; i <= n; i ++)
{
for(int j = x; j <= m; j ++)
{
int x1 = i - x + 1;
int y1 = j - x + 1;
int x2 = i;
int y2 = j;
if(sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1] == ans)
return true;
}
}
return false;
}
int maximalSquare(vector<vector<char>>& matrix) {
int n = matrix.size();
int m = matrix[0].size();
vector<vector<int>>sum;
sum.resize(n + 1, vector<int>(m + 1, 0));
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + (matrix[i - 1][j - 1] == '1');
//cout << sum[i][j] << endl;
}
int l = 0, r = min(n, m);
while(l <= r)
{
int mid = l + (r + 1) >> 1;
if(check(mid, n, m, sum)) l = mid + 1;
else r = mid - 1;
}
return (l - 1) * (l - 1);
}
};
第二种方法:DP(动态规划)
题解来源:该题官网题解。
时间复杂度:
这里仅解释一下为什么转移方程是
通俗易懂得理解方法是,因为本题需要得是正方形,因此仅需要保证周围点为1且加上自己构成正方形即可。如果左、上、左上有一个点为0,那么将无法转移。至于为什么不会被判断成长方形呢?可以看到
代码2:
cpp
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
int n = matrix.size();
int m = matrix[0].size();
int ans = 0;
vector<vector<int>>dp(n + 1, vector<int>(m + 1, 0));
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
if(matrix[i-1][j-1] == '0') dp[i][j] = 0;
else
{
dp[i][j] = min(dp[i-1][j], min(dp[i][j-1], dp[i-1][j-1])) + 1;//保证周围点为正方形
}
ans = max(ans, dp[i][j]);
}
}
return ans * ans;
}
};
思考:
思考二:如果是求长方形,又该如何去做?
这个题就会变得非常有趣。动态规划应该依旧有求解得办法,但是原方程必定失效。而这个题是LeetCode 85 85.最大矩形. - 力扣(LeetCode)得题,使用的是单调栈来求解,我将在后续对这个题单独学习。