Output: 3 Explanation: The maximum length of a side of the square sub-matrix is 3 where every element is 1.
Input: mat[][] = [[1, 1], [1, 1]] Output: 2 Explanation: The maximum length of a side of the square sub-matrix is 2. The matrix itself is the maximum sized sub-matrix in this case.
[Naive Approach] - Using Recursion - O(3^(n+m)) Time and O(n+m) Space
The idea is to recursively determine the side length of the largest square sub-matrix with all 1s at each cell. For each cell, if its value is 0, we return 0 since it cannot contribute to a square. Otherwise, we calculate the possible side length of a square ending at this cell by finding the minimum square side lengths from the right, bottom, and bottom-right diagonal cells and adding 1 to this minimum. This value gives the largest possible square side length for that cell, and we update the maximum side length by comparing it with the result at each cell.
The recurrence equation will be as follows:
Side(i, j) = 1 + minimum(Side(i, j+1), Side(i+1, j), Side(i+1, j+1)) for cells i, j where mat[i][j] = 1.
Otherwise Side(i,j) = 0.
C++
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;//recursive function to find the squareintmaxSquareRecur(inti,intj,vector<vector<int>>&mat,int&ans){// Return 0 for invalid cellsif(i<0||i==mat.size()||j<0||j==mat[0].size())return0;// for the side squareintright=maxSquareRecur(i,j+1,mat,ans);intdown=maxSquareRecur(i+1,j,mat,ans);intdiagonal=maxSquareRecur(i+1,j+1,mat,ans);// If mat[i][j]==0, then square cannot// be formed.if(mat[i][j]==0)return0;// Side of square will be intval=1+min({right,down,diagonal});ans=max(ans,val);returnval;}// for calculate the answerintmaxSquare(vector<vector<int>>&mat){intans=0;maxSquareRecur(0,0,mat,ans);returnans;}intmain(){vector<vector<int>>mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};cout<<maxSquare(mat)<<endl;return0;}
Java
publicclassGfG{// recursive function to find the squarestaticintmaxSquareRecur(inti,intj,int[][]mat,int[]ans){// Return 0 for invalid cellsif(i<0||i==mat.length||j<0||j==mat[0].length)return0;// for the side squareintright=maxSquareRecur(i,j+1,mat,ans);intdown=maxSquareRecur(i+1,j,mat,ans);intdiagonal=maxSquareRecur(i+1,j+1,mat,ans);// If mat[i][j]==0, then square cannot be formed.if(mat[i][j]==0)return0;// Side of square will beintval=1+Math.min(right,Math.min(down,diagonal));ans[0]=Math.max(ans[0],val);returnval;}// for calculate the answerstaticintmaxSquare(int[][]mat){int[]ans=newint[1];maxSquareRecur(0,0,mat,ans);returnans[0];}publicstaticvoidmain(String[]args){int[][]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};System.out.println(maxSquare(mat));}}
Python
# recursive function to find the squaredefmaxSquareRecur(i,j,mat,ans):# Return 0 for invalid cellsifi<0ori==len(mat)orj<0orj==len(mat[0]):return0# for the side squareright=maxSquareRecur(i,j+1,mat,ans)down=maxSquareRecur(i+1,j,mat,ans)diagonal=maxSquareRecur(i+1,j+1,mat,ans)# If mat[i][j]==0, then square cannot be formed.ifmat[i][j]==0:return0# Side of square will beval=1+min(right,down,diagonal)ans[0]=max(ans[0],val)returnval# for calculate the answerdefmaxSquare(mat):ans=[0]maxSquareRecur(0,0,mat,ans)returnans[0]if__name__=="__main__":mat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]]print(maxSquare(mat))
C#
usingSystem;classGfG{// recursive function to find the squarestaticintMaxSquareRecur(inti,intj,int[,]mat,refintans){introws=mat.GetLength(0);intcols=mat.GetLength(1);// Return 0 for invalid cellsif(i<0||i==rows||j<0||j==cols)return0;// for the side squareintright=MaxSquareRecur(i,j+1,mat,refans);intdown=MaxSquareRecur(i+1,j,mat,refans);intdiagonal=MaxSquareRecur(i+1,j+1,mat,refans);// If mat[i][j]==0, then square cannot be formed.if(mat[i,j]==0)return0;// Side of square will beintval=1+Math.Min(right,Math.Min(down,diagonal));ans=Math.Max(ans,val);returnval;}// for calculate the answerstaticintMaxSquare(int[,]mat){intans=0;MaxSquareRecur(0,0,mat,refans);returnans;}staticvoidMain(){int[,]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};Console.WriteLine(MaxSquare(mat));}}
JavaScript
// recursive function to find the squarefunctionmaxSquareRecur(i,j,mat,ans){// Return 0 for invalid cellsif(i<0||i==mat.length||j<0||j==mat[0].length)return0;// for the side squareletright=maxSquareRecur(i,j+1,mat,ans);letdown=maxSquareRecur(i+1,j,mat,ans);letdiagonal=maxSquareRecur(i+1,j+1,mat,ans);// If mat[i][j]==0, then square cannot be formed.if(mat[i][j]===0)return0;// Side of square will beletval=1+Math.min(right,down,diagonal);ans.value=Math.max(ans.value,val);returnval;}// for calculate the answerfunctionmaxSquare(mat){letans={value:0};maxSquareRecur(0,0,mat,ans);returnans.value;}// Driver codeletmat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]];console.log(maxSquare(mat));
Output
3
[Better Approach - 1] - Using Top-Down DP ( Memoization) - O(n × m) Time and O(n × m) Space
The recursive calls use sub-problems so if we get a sub-problem the first time, we can solve this problem by creating a 2-D array that can store a particular state. Now if we come across the same state again instead of calculating it again we can directly return its result stored in the table in constant time.
The recursive solution holds the following two properties of Dynamic Programming:
1. Optimal Substructure:
The side of square originating from i, j, i.e., maxSquare(i, j), depends on the optimal solutions of the sub-problems maxSquare(i, j+1) , maxSquare(i+1, j) and maxSquare(i+1, j+1). By finding the minimum value in these optimal substructures, we can efficiently calculate the side of square at (i,j).
2. Overlapping Sub-problems:
While applying a recursive approach in this problem, we notice that certain sub-problems are computed multiple times.
There aretwo parameters, i and j that changes in the recursivesolution. So we create a 2D array of size n × m for memoization.
We initialize thisarray as -1 to indicate nothing is computed initially.
Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same sub-problems.
C++
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;// recursive function to find the squareintmaxSquareRecur(inti,intj,vector<vector<int>>&mat,int&ans,vector<vector<int>>&memo){// Return 0 for invalid cellsif(i<0||i==mat.size()||j<0||j==mat[0].size())return0;// If value is memoized, return value.if(memo[i][j]!=-1)returnmemo[i][j];// for the side squareintright=maxSquareRecur(i,j+1,mat,ans,memo);intdown=maxSquareRecur(i+1,j,mat,ans,memo);intdiagonal=maxSquareRecur(i+1,j+1,mat,ans,memo);// If mat[i][j]==0, then square cannot// be formed.if(mat[i][j]==0)returnmemo[i][j]=0;// Side of square will be intval=1+min({right,down,diagonal});ans=max(ans,val);// Memoize the value and return it.returnmemo[i][j]=val;}intmaxSquare(vector<vector<int>>&mat){intn=mat.size(),m=mat[0].size();intans=0;// Create 2d array for memoizationvector<vector<int>>memo(n,vector<int>(m,-1));maxSquareRecur(0,0,mat,ans,memo);returnans;}intmain(){vector<vector<int>>mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};cout<<maxSquare(mat)<<endl;return0;}
Java
importjava.util.Arrays;classGfG{// recursive function to find the squarestaticintmaxSquareRecur(inti,intj,int[][]mat,int[]ans,int[][]memo){// Return 0 for invalid cellsif(i<0||i==mat.length||j<0||j==mat[0].length)return0;// If value is memoized, return value.if(memo[i][j]!=-1)returnmemo[i][j];// for the side squareintright=maxSquareRecur(i,j+1,mat,ans,memo);intdown=maxSquareRecur(i+1,j,mat,ans,memo);intdiagonal=maxSquareRecur(i+1,j+1,mat,ans,memo);// If mat[i][j]==0, then square cannot// be formed.if(mat[i][j]==0)returnmemo[i][j]=0;// Side of square will beintval=1+Math.min(right,Math.min(down,diagonal));ans[0]=Math.max(ans[0],val);// Memoize the value and return it.returnmemo[i][j]=val;}staticintmaxSquare(int[][]mat){intn=mat.length,m=mat[0].length;int[]ans={0};// Create 2d array for memoizationint[][]memo=newint[n][m];for(int[]row:memo)Arrays.fill(row,-1);maxSquareRecur(0,0,mat,ans,memo);returnans[0];}publicstaticvoidmain(String[]args){int[][]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};System.out.println(maxSquare(mat));}}
Python
# recursive function to find the squaredefmaxSquareRecur(i,j,mat,ans,memo):# Return 0 for invalid cellsifi<0ori==len(mat)orj<0orj==len(mat[0]):return0# If value is memoized, return value.ifmemo[i][j]!=-1:returnmemo[i][j]# for the side squareright=maxSquareRecur(i,j+1,mat,ans,memo)down=maxSquareRecur(i+1,j,mat,ans,memo)diagonal=maxSquareRecur(i+1,j+1,mat,ans,memo)# If mat[i][j]==0, then square cannot# be formed.ifmat[i][j]==0:memo[i][j]=0return0# Side of square will beval=1+min(right,down,diagonal)ans[0]=max(ans[0],val)# Memoize the value and return it.memo[i][j]=valreturnvaldefmaxSquare(mat):n,m=len(mat),len(mat[0])ans=[0]# Create 2d array for memoizationmemo=[[-1for_inrange(m)]for_inrange(n)]maxSquareRecur(0,0,mat,ans,memo)returnans[0]if__name__=="__main__":mat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]]print(maxSquare(mat))
C#
usingSystem;classGfG{// recursive function to find the squarestaticintmaxSquareRecur(inti,intj,int[,]mat,int[]ans,int[,]memo){// Return 0 for invalid cellsif(i<0||i==mat.GetLength(0)||j<0||j==mat.GetLength(1))return0;// If value is memoized, return value.if(memo[i,j]!=-1)returnmemo[i,j];// for the side squareintright=maxSquareRecur(i,j+1,mat,ans,memo);intdown=maxSquareRecur(i+1,j,mat,ans,memo);intdiagonal=maxSquareRecur(i+1,j+1,mat,ans,memo);// If mat[i][j]==0, then square cannot// be formed.if(mat[i,j]==0)returnmemo[i,j]=0;// Side of square will beintval=1+Math.Min(right,Math.Min(down,diagonal));ans[0]=Math.Max(ans[0],val);// Memoize the value and return it.returnmemo[i,j]=val;}staticintmaxSquare(int[,]mat){intn=mat.GetLength(0),m=mat.GetLength(1);int[]ans={0};// Create 2d array for memoizationint[,]memo=newint[n,m];for(inti=0;i<n;i++)for(intj=0;j<m;j++)memo[i,j]=-1;maxSquareRecur(0,0,mat,ans,memo);returnans[0];}staticvoidMain(){int[,]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};Console.WriteLine(maxSquare(mat));}}
JavaScript
// recursive function to find the squarefunctionmaxSquareRecur(i,j,mat,ans,memo){// Return 0 for invalid cellsif(i<0||i===mat.length||j<0||j===mat[0].length)return0;// If value is memoized, return value.if(memo[i][j]!==-1)returnmemo[i][j];// for the side squareletright=maxSquareRecur(i,j+1,mat,ans,memo);letdown=maxSquareRecur(i+1,j,mat,ans,memo);letdiagonal=maxSquareRecur(i+1,j+1,mat,ans,memo);// If mat[i][j]==0, then square cannot// be formed.if(mat[i][j]===0)returnmemo[i][j]=0;// Side of square will beletval=1+Math.min(right,down,diagonal);ans[0]=Math.max(ans[0],val);// Memoize the value and return it.memo[i][j]=val;returnval;}functionmaxSquare(mat){letn=mat.length,m=mat[0].length;letans=[0];// Create 2d array for memoizationletmemo=Array.from({length:n},()=>Array(m).fill(-1));maxSquareRecur(0,0,mat,ans,memo);returnans[0];}letmat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]];console.log(maxSquare(mat));
Output
3
[Better Approach - 2] -Using Bottom-Up DP (Tabulation) – O(n × m) Time and O(n × m) Space
The approach is similar to the previous one, just instead of breaking down the problem recursively, we iteratively build up the solution by calculating in bottom-up manner. The idea is to create a 2-D array. Then fill the values using dp[i][j] = 1 + min(dp[i+1][j], dp[i][j+1], dp[i+1][j+1]) for cells having value equal to 1. Otherwise, set dp[i][j] = 0.
C++
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmaxSquare(vector<vector<int>>&mat){intn=mat.size(),m=mat[0].size();intans=0;// Create 2d array for tabulationvector<vector<int>>dp(n+1,vector<int>(m+1,0));// Fill the dp for(inti=n-1;i>=0;i--){for(intj=m-1;j>=0;j--){// If square cannot be formedif(mat[i][j]==0){dp[i][j]=0;continue;}// check all 3 sidesdp[i][j]=1+min({dp[i][j+1],dp[i+1][j],dp[i+1][j+1]});ans=max(ans,dp[i][j]);}}returnans;}intmain(){vector<vector<int>>mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};cout<<maxSquare(mat)<<endl;return0;}
Java
publicclassGfG{staticintmaxSquare(int[][]mat){intn=mat.length,m=mat[0].length;intans=0;// Create 2d array for tabulationint[][]dp=newint[n+1][m+1];// Fill the dpfor(inti=n-1;i>=0;i--){for(intj=m-1;j>=0;j--){// If square cannot be formedif(mat[i][j]==0){dp[i][j]=0;continue;}// check all 3 sidesdp[i][j]=1+Math.min(dp[i][j+1],Math.min(dp[i+1][j],dp[i+1][j+1]));ans=Math.max(ans,dp[i][j]);}}returnans;}publicstaticvoidmain(String[]args){int[][]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};System.out.println(maxSquare(mat));}}
Python
defmaxSquare(mat):n=len(mat)m=len(mat[0])ans=0# Create 2d array for tabulationdp=[[0]*(m+1)for_inrange(n+1)]# Fill the dpforiinrange(n-1,-1,-1):forjinrange(m-1,-1,-1):# If square cannot be formedifmat[i][j]==0:dp[i][j]=0continue# check all 3 sidesdp[i][j]=1+min(dp[i][j+1],dp[i+1][j],dp[i+1][j+1])ans=max(ans,dp[i][j])returnansmat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]]print(maxSquare(mat))
C#
usingSystem;classGfG{staticintMaxSquare(int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);intans=0;// Create 2d array for tabulationint[,]dp=newint[n+1,m+1];// Fill the dpfor(inti=n-1;i>=0;i--){for(intj=m-1;j>=0;j--){// If square cannot be formedif(mat[i,j]==0){dp[i,j]=0;continue;}// check all 3 sidesdp[i,j]=1+Math.Min(dp[i,j+1],Math.Min(dp[i+1,j],dp[i+1,j+1]));ans=Math.Max(ans,dp[i,j]);}}returnans;}staticvoidMain(){int[,]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};Console.WriteLine(MaxSquare(mat));}}
JavaScript
functionmaxSquare(mat){letn=mat.length,m=mat[0].length;letans=0;// Create 2d array for tabulationletdp=Array.from({length:n+1},()=>Array(m+1).fill(0));// Fill the dpfor(leti=n-1;i>=0;i--){for(letj=m-1;j>=0;j--){// If square cannot be formedif(mat[i][j]===0){dp[i][j]=0;continue;}// check all 3 sidesdp[i][j]=1+Math.min(dp[i][j+1],dp[i+1][j],dp[i+1][j+1]);ans=Math.max(ans,dp[i][j]);}}returnans;}// Driver codeletmat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]];console.log(maxSquare(mat));
Output
3
[Expected Approach] - Using Space Optimized DP – O(n × m) Time and O(n) Space
The idea is store the values for the next column only. We can observe that for a given cell (i,j), its value is only dependent on the two cells of the next column and the bottom cell of current column.
C++
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmaxSquare(vector<vector<int>>&mat){intn=mat.size(),m=mat[0].size();intans=0;// dp to store the result vector<int>dp(n+1,0);intdiagonal=0;// Traverse column by columnfor(intj=m-1;j>=0;j--){for(inti=n-1;i>=0;i--){inttmp=dp[i];// If square cannot be formedif(mat[i][j]==0){dp[i]=0;}else{dp[i]=1+min({dp[i],diagonal,dp[i+1]});}diagonal=tmp;ans=max(ans,dp[i]);}}returnans;}intmain(){vector<vector<int>>mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};cout<<maxSquare(mat)<<endl;return0;}
Java
publicclassGfG{staticintmaxSquare(int[][]mat){intn=mat.length,m=mat[0].length;intans=0;// dp to store the result int[]dp=newint[n+1];intdiagonal=0;// Traverse column by columnfor(intj=m-1;j>=0;j--){diagonal=0;for(inti=n-1;i>=0;i--){inttmp=dp[i];// If square cannot be formedif(mat[i][j]==0){dp[i]=0;}else{dp[i]=1+Math.min(dp[i],Math.min(diagonal,dp[i+1]));}diagonal=tmp;ans=Math.max(ans,dp[i]);}}returnans;}publicstaticvoidmain(String[]args){int[][]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};System.out.println(maxSquare(mat));}}
Python
defmaxSquare(mat):n=len(mat)m=len(mat[0])ans=0# dp to store the result dp=[0]*(n+1)diagonal=0# Traverse column by columnforjinrange(m-1,-1,-1):diagonal=0foriinrange(n-1,-1,-1):tmp=dp[i]# If square cannot be formedifmat[i][j]==0:dp[i]=0else:dp[i]=1+min(dp[i],diagonal,dp[i+1])diagonal=tmpans=max(ans,dp[i])returnansif__name__=="__main__":mat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]]print(maxSquare(mat))
C#
usingSystem;classGfG{staticintMaxSquare(int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);intans=0;// dp to store the result int[]dp=newint[n+1];intdiagonal=0;// Traverse column by columnfor(intj=m-1;j>=0;j--){diagonal=0;for(inti=n-1;i>=0;i--){inttmp=dp[i];// If square cannot be formedif(mat[i,j]==0){dp[i]=0;}else{dp[i]=1+Math.Min(dp[i],Math.Min(diagonal,dp[i+1]));}diagonal=tmp;ans=Math.Max(ans,dp[i]);}}returnans;}staticvoidMain(){int[,]mat={{0,1,1,0,1},{1,1,0,1,0},{0,1,1,1,0},{1,1,1,1,0},{1,1,1,1,1},{0,0,0,0,0}};Console.WriteLine(MaxSquare(mat));}}
JavaScript
functionmaxSquare(mat){letn=mat.length,m=mat[0].length;letans=0;// dp to store the result letdp=newArray(n+1).fill(0);letdiagonal=0;// Traverse column by columnfor(letj=m-1;j>=0;j--){diagonal=0;for(leti=n-1;i>=0;i--){lettmp=dp[i];// If square cannot be formedif(mat[i][j]===0){dp[i]=0;}else{dp[i]=1+Math.min(dp[i],diagonal,dp[i+1]);}diagonal=tmp;ans=Math.max(ans,dp[i]);}}returnans;}// Driver codeletmat=[[0,1,1,0,1],[1,1,0,1,0],[0,1,1,1,0],[1,1,1,1,0],[1,1,1,1,1],[0,0,0,0,0]];console.log(maxSquare(mat));