第一种解法:二维前缀和暴力
维护一个二维的前缀和f[i][j]表示从(1,1)到(i,j)的正方形矩阵的和。f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]
然后枚举每个点,并假设该点为右下角顶点,然后枚举正方形长度判断满不满足条件即可,条件为:f[i][j]-f[i-k][j]-f[i][j-k]+f[i-k][j-k]==k*k
code:
class Solution { public: int dp[1000][1000]; int maximalSquare(vector<vector<char>>& matrix) { int n=matrix.size(); if(n==0) return 0; int m=matrix[0].size(); for(int i=1;i<=n;i++){ if(matrix[i-1][0]=='1'){ dp[i][1]+=1+dp[i-1][1]; } else dp[i][1]+=dp[i-1][1]; } for(int i=2;i<=m;i++){ if(matrix[0][i-1]=='1'){ dp[1][i]+=dp[1][i-1]+1; } else dp[1][i]+=dp[1][i-1]; } for(int i=2;i<=n;i++){ for(int j=2;j<=m;j++){ dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]; if(matrix[i-1][j-1]=='1') dp[i][j]+=1; } } 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 ; int c=min(i,j); for(int k=1;k<=c;k++){ if(dp[i][j]-dp[i-k][j]-dp[i][j-k]+dp[i-k][j-k]==k*k) ans=max(ans,k*k); else break; } } } return ans; } };
第二种解法:dp
定义dp[i][j]表示以(i,j)为右下角点所能构成的正方形的最大边长。
dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
方程证明:
假如说我们dp[i][j]由dp[i-1][j]即i,j上边的点转移过来,因为他是正方形,所以高度和宽度应该同时加一。新正方形以(i,j)为右下角的边长为dp[i-1][j]+1,也就是说从 (i,j)到点(i-dp[i-1][j],j)都应该是1,我们再来看看(i,j-1)这个点,他的正方形边长为dp[i][j-1]。即从(i-1,j)到(i-dp[i][j-1],j-1)都应该是1.所以应该满足i-dp[i][j-1]<=i-dp[i-1][j];即dp[i-1][j]<=dp[i][j-1]。同理可得dp[i-1][j]<=dp[i-1][j-1]即我们选择的总是三个里边最小的。
code:
class Solution { public: int dp[1000][1000]; int maximalSquare(vector<vector<char>>& matrix) { int n=matrix.size(); if(n==0) return 0; int m=matrix[0].size(); int ans=0; for(int i=1;i<=n;i++){ if(matrix[i-1][0]=='1'){ dp[i][1]=1; ans=1; } } for(int j=1;j<=m;j++){ if(matrix[0][j-1]=='1') { dp[1][j]=1; ans=1; } } for(int i=2;i<=n;i++){ for(int j=2;j<=m;j++){ if(matrix[i-1][j-1]=='1') { 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; } };