- 二维数组的前缀和、二分查找
时间复杂度 :
大概思路:
用二维数组前缀和预处理,然后枚举矩阵中的每一个点,以此点作为正方形的左上角,然后二分求出能够构成的最大正方形(用前缀和快速求出某个字块是否全为1),累积进答案。
class Solution {
public:
vector<vector<int>> s;
int countSquares(vector<vector<int>>& a) {
int ans = 0, m = a.size(), n = a[0].size();
s.resize(m+1,vector<int>(n+1,0));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
s[i][j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i-1][j-1];
}
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
int l = 1,r = min(m+1-i,n+1-j),res=0;
while(l<=r){
int mid = (l+r)/2;
if(checkSquare(i,j,mid)){
res = max(res,mid);
l = mid+1;
}else{
r = mid-1;
}
}
ans += res;
}
}
return ans;
}
bool checkSquare(int x,int y,int l){
return getSum(x,y,x+l-1,y+l-1) == l*l;
}
int getSum(int x1,int y1,int x2,int y2){
return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
}
};
DP:
相似的一道题目
现在枚举正方形的个数,就是以右下角为起点,然后边长递增。
表示以
为右下角的正方形的最大边长,然后以
为右下角的正方形的个数就是边长
,累积进答案。
时间复杂度:
class Solution {
public:
int countSquares(vector<vector<int>>& a) {
if(a.size()==0 || a[0].size()==0) return 0;
int m = a.size(), n = a[0].size(),ans = 0;
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(a[i-1][j-1]==0){
dp[i][j] = 0;
}else{
int s1 = dp[i-1][j-1];
int s2 = dp[i-1][j];
int s3 = dp[i][j-1];
dp[i][j] = min(min(s1,s2),s3)+1;
}
ans += dp[i][j];
}
}
return ans;
}
};