Given a matrix where every element is either ‘O’ or ‘X’, find the largest subsquare surrounded by ‘X’.
In the below article, it is assumed that the given matrix is also a square matrix. The code given below can be easily extended for rectangular matrices.
Examples:
Input: mat[N][N] = { {'X', 'O', 'X', 'X', 'X'},
{'X', 'X', 'X', 'X', 'X'},
{'X', 'X', 'O', 'X', 'O'},
{'X', 'X', 'X', 'X', 'X'},
{'X', 'X', 'X', 'O', 'O'},
};
Output: 3
The square submatrix starting at (1, 1) is the largest
submatrix surrounded by 'X'
Input: mat[M][N] = { {'X', 'O', 'X', 'X', 'X', 'X'},
{'X', 'O', 'X', 'X', 'O', 'X'},
{'X', 'X', 'X', 'O', 'O', 'X'},
{'X', 'X', 'X', 'X', 'X', 'X'},
{'X', 'X', 'X', 'O', 'X', 'O'},
};
Output: 4
The square submatrix starting at (0, 2) is the largest
submatrix surrounded by 'X'
A Simple Solution is to consider every square submatrix and check whether is has all corner edges filled with ‘X’. The time complexity of this solution is O(N4).
We can solve this problem in O(N3) time using extra space. The idea is to create two auxiliary arrays hor[N][N] and ver[N][N]. The value stored in hor[i][j] is the number of horizontal continuous ‘X’ characters till mat[i][j] in mat[][]. Similarly, the value stored in ver[i][j] is the number of vertical continuous ‘X’ characters till mat[i][j] in mat[][].
Example:
mat[6][6] = X O X X X X
X O X X O X
X X X O O X
O X X X X X
X X X O X O
O O X O O O
hor[6][6] = 1 0 1 2 3 4
1 0 1 2 0 1
1 2 3 0 0 1
0 1 2 3 4 5
1 2 3 0 1 0
0 0 1 0 0 0
ver[6][6] = 1 0 1 1 1 1
2 0 2 2 0 2
3 1 3 0 0 3
0 2 4 1 1 4
1 3 5 0 2 0
0 0 6 0 0 0
Once we have filled values in hor[][] and ver[][], we start from the bottommost-rightmost corner of matrix and move toward the leftmost-topmost in row by row manner. For every visited entry mat[i][j], we compare the values of hor[i][j] and ver[i][j], and pick the smaller of two as we need a square. Let the smaller of two be ‘small’. After picking smaller of two, we check if both ver[][] and hor[][] for left and up edges respectively. If they have entries for the same, then we found a subsquare. Otherwise we try for small-1.
Below is implementation of the above idea.
C++
#include <iostream>
using namespace std;
#define N 6
int getMin( int x, int y) { return (x < y) ? x : y; }
int findSubSquare( int mat[][N])
{
int max = 0;
int hor[N][N], ver[N][N];
hor[0][0] = ver[0][0] = (mat[0][0] == 'X' );
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < N; j++)
{
if (mat[i][j] == 'O' )
ver[i][j] = hor[i][j] = 0;
else
{
hor[i][j]
= (j == 0) ? 1 : hor[i][j - 1] + 1;
ver[i][j]
= (i == 0) ? 1 : ver[i - 1][j] + 1;
}
}
}
for ( int i = N - 1; i >= 1; i--)
{
for ( int j = N - 1; j >= 1; j--)
{
int small = getMin(hor[i][j], ver[i][j]);
while (small > max)
{
if (ver[i][j - small + 1] >= small
&& hor[i - small + 1][j] >= small)
{
max = small;
}
small--;
}
}
}
return max;
}
int main()
{
int mat[][N] = {
{ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' },
{ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' },
{ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' },
};
cout << findSubSquare(mat);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static int N = 6 ;
static int getMin( int x, int y)
{
return (x < y) ? x : y;
}
static int findSubSquare( int mat[][])
{
int max = 0 ;
int hor[][] = new int [N][N];
int ver[][] = new int [N][N];
hor[ 0 ][ 0 ] = ver[ 0 ][ 0 ] = 'X' ;
for ( int i = 0 ; i < N; i++)
{
for ( int j = 0 ; j < N; j++)
{
if (mat[i][j] == 'O' )
ver[i][j] = hor[i][j] = 0 ;
else
{
hor[i][j]
= (j == 0 ) ? 1 : hor[i][j - 1 ] + 1 ;
ver[i][j]
= (i == 0 ) ? 1 : ver[i - 1 ][j] + 1 ;
}
}
}
for ( int i = N - 1 ; i >= 1 ; i--)
{
for ( int j = N - 1 ; j >= 1 ; j--)
{
int small = getMin(hor[i][j], ver[i][j]);
while (small > max)
{
if (ver[i][j - small + 1 ] >= small
&& hor[i - small + 1 ][j] >= small)
{
max = small;
}
small--;
}
}
}
return max;
}
public static void main(String[] args)
{
int mat[][] = { { 'X' , 'O' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' },
{ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' },
{ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' } };
System.out.println(findSubSquare(mat));
}
}
|
Python3
import math as mt
N = 6
def getMin(x, y):
if x < y:
return x
else :
return y
def findSubSquare(mat):
Max = 0
hor = [[ 0 for i in range (N)]
for i in range (N)]
ver = [[ 0 for i in range (N)]
for i in range (N)]
if mat[ 0 ][ 0 ] = = 'X' :
hor[ 0 ][ 0 ] = 1
ver[ 0 ][ 0 ] = 1
for i in range (N):
for j in range (N):
if (mat[i][j] = = 'O' ):
ver[i][j], hor[i][j] = 0 , 0
else :
if j = = 0 :
ver[i][j], hor[i][j] = 1 , 1
else :
(ver[i][j],
hor[i][j]) = (ver[i - 1 ][j] + 1 ,
hor[i][j - 1 ] + 1 )
for i in range (N - 1 , 0 , - 1 ):
for j in range (N - 1 , 0 , - 1 ):
small = getMin(hor[i][j], ver[i][j])
while (small > Max ):
if (ver[i][j - small + 1 ] > = small and
hor[i - small + 1 ][j] > = small):
Max = small
small - = 1
return Max
mat = [[ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' ],
[ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' ],
[ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' ]]
print (findSubSquare(mat))
|
C#
using System;
class GFG
{
static int N = 6;
static int getMin( int x, int y)
{
return (x < y) ? x : y;
}
static int findSubSquare( int [, ] mat)
{
int max = 0;
int [, ] hor = new int [N, N];
int [, ] ver = new int [N, N];
hor[0, 0] = ver[0, 0] = 'X' ;
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < N; j++)
{
if (mat[i, j] == 'O' )
ver[i, j] = hor[i, j] = 0;
else
{
hor[i, j]
= (j == 0) ? 1 : hor[i, j - 1] + 1;
ver[i, j]
= (i == 0) ? 1 : ver[i - 1, j] + 1;
}
}
}
for ( int i = N - 1; i >= 1; i--)
{
for ( int j = N - 1; j >= 1; j--)
{
int small = getMin(hor[i, j], ver[i, j]);
while (small > max)
{
if (ver[i, j - small + 1] >= small
&& hor[i - small + 1, j] >= small)
{
max = small;
}
small--;
}
}
}
return max;
}
public static void Main()
{
int [, ] mat = { { 'X' , 'O' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' },
{ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' },
{ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' } };
Console.WriteLine(findSubSquare(mat));
}
}
|
PHP
<?php
$N = 6;
function getMin( $x , $y )
{
return ( $x < $y ) ? $x : $y ;
}
function findSubSquare( $mat )
{
$max = 0;
$hor [0][0] = $ver [0][0] = ( $mat [0][0] == 'X' );
for ( $i = 0; $i < $GLOBALS [ 'N' ]; $i ++)
{
for ( $j = 0; $j < $GLOBALS [ 'N' ]; $j ++)
{
if ( $mat [ $i ][ $j ] == 'O' )
$ver [ $i ][ $j ] = $hor [ $i ][ $j ] = 0;
else
{
$hor [ $i ][ $j ] = ( $j == 0) ? 1 :
$hor [ $i ][ $j - 1] + 1;
$ver [ $i ][ $j ] = ( $i == 0) ? 1 :
$ver [ $i - 1][ $j ] + 1;
}
}
}
for ( $i = $GLOBALS [ 'N' ] - 1; $i >= 1; $i --)
{
for ( $j = $GLOBALS [ 'N' ] - 1; $j >= 1; $j --)
{
$small = getMin( $hor [ $i ][ $j ],
$ver [ $i ][ $j ]);
while ( $small > $max )
{
if ( $ver [ $i ][ $j - $small + 1] >= $small &&
$hor [ $i - $small + 1][ $j ] >= $small )
{
$max = $small ;
}
$small --;
}
}
}
return $max ;
}
$mat = array ( array ( 'X' , 'O' , 'X' , 'X' , 'X' , 'X' ),
array ( 'X' , 'O' , 'X' , 'X' , 'O' , 'X' ),
array ( 'X' , 'X' , 'X' , 'O' , 'O' , 'X' ),
array ( 'O' , 'X' , 'X' , 'X' , 'X' , 'X' ),
array ( 'X' , 'X' , 'X' , 'O' , 'X' , 'O' ),
array ( 'O' , 'O' , 'X' , 'O' , 'O' , 'O' ));
echo findSubSquare( $mat );
?>
|
Javascript
<script>
let N = 6;
function getMin(x,y)
{
return (x < y) ? x : y;
}
function findSubSquare(mat)
{
let max = 0;
let hor = new Array(N);
let ver = new Array(N);
for (let i = 0; i < N; i++)
{
hor[i]= new Array(N);
ver[i]= new Array(N);
for (let j = 0; j < N; j++)
{
hor[i][j]= "" ;
ver[i][j]= "" ;
}
}
hor[0][0] = 'X' ;
ver[0][0] = 'X' ;
for (let i = 0; i < N; i++)
{
for (let j = 0; j < N; j++)
{
if (mat[i][j] == 'O' )
ver[i][j] = hor[i][j] = 0;
else
{
hor[i][j]
= (j == 0) ? 1 : hor[i][j - 1] + 1;
ver[i][j]
= (i == 0) ? 1 : ver[i - 1][j] + 1;
}
}
}
for (let i = N - 1; i >= 1; i--)
{
for (let j = N - 1; j >= 1; j--)
{
let small = getMin(hor[i][j], ver[i][j]);
while (small > max)
{
if (ver[i][j - small + 1] >= small
&& hor[i - small + 1][j] >= small)
{
max = small;
}
small--;
}
}
}
return max;
}
let mat = [[ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' ],
[ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' ],
[ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' ]]
document.write(findSubSquare(mat))
</script>
|
Time complexity: O(N2).
Auxiliary Space: O(N2)
Optimized approach:
A more optimized solution would be to pre-compute the number of contiguous ‘X’ horizontally and vertically, in a matrix of pairs named dp. Now for every entry of dp we have a pair (int, int) which denotes the maximum contiguous ‘X’ till that point, i.e.
- dp[i][j].first denotes contiguous ‘X’ taken horizontally till that point.
- dp[i][j].second denotes contiguous ‘X’ taken vertically till that point.
Now, a square can be formed with dp[i][j] as the bottom right corner, having sides atmost of length, min(dp[i][j].first, dp[i][j].second)
So, we make another matrix maxside, which will denote the maximum square side formed having the bottom right corner as arr[i][j]. We’ll try to get some intuition from the properties of a square, i.e. all the sides of the square are equal.
Let’s store maximum value that can be obtained, as val = min(dp[i][j].first, dp[i][j].second). From point (i, j), we traverse back horizontally by distance Val, and check if the minimum vertical contiguous ‘X’ till that point is equal to Val.
Similarly, we traverse back vertically by distance Val and check if the minimum horizontal contiguous ‘X’ till that point is equal to Val? Here we are making use of the fact that all sides of square are equal.
Input Matrix:
X O X X X X
X O X X O X
X X X O O X
O X X X X X
X X X O X O
O O X O O O
Value of matrix dp:
(1,1) (0,0) (1,1) (2,1) (3,1) (4,1)
(1,2) (0,0) (1,2) (2,2) (0,0) (1,2)
(1,3) (2,1) (3,3) (0,0) (0,0) (1,3)
(0,0) (1,2) (2,4) (3,1) (4,1) (5,4)
(1,1) (2,3) (3,5) (0,0) (1,2) (0,0)
(0,0) (0,0) (1,6) (0,0) (0,0) (0,0)
Below is the implementation of the above idea:
C++
#include <bits/stdc++.h>
using namespace std;
#define N 6
int maximumSubSquare( int arr[][N])
{
pair< int , int > dp[51][51];
int maxside[51][51];
memset (maxside, 0, sizeof (maxside));
int x = 0, y = 0;
for ( int i = 0; i < N; i++)
{
x = 0;
for ( int j = 0; j < N; j++)
{
if (arr[i][j] == 'X' )
x += 1;
else
x = 0;
dp[i][j].first = x;
}
}
for ( int i = 0; i < N; i++)
{
y=0;
for ( int j = 0; j < N; j++)
{
if (arr[j][i] == 'X' )
y += 1;
else
y = 0;
dp[j][i].second = y;
}
}
int maxval = 0, val = 0;
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < N; j++)
{
val = min(dp[i][j].first, dp[i][j].second);
if (dp[i][j - val + 1].second >= val
&& dp[i - val + 1][j].first >= val)
maxside[i][j] = val;
else
maxside[i][j] = 0;
maxval = max(maxval, maxside[i][j]);
}
}
return maxval;
}
int main()
{
int mat[][N] = {
{ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' },
{ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' },
{ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' },
};
cout << maximumSubSquare(mat);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG
{
static int N = 6 ;
static int maximumSubSquare( int [][] arr)
{
int [][][] dp = new int [ 51 ][ 51 ][ 2 ];
int [][] maxside = new int [ 51 ][ 51 ];
for ( int [] row : maxside)
Arrays.fill(row, 10 );
int x = 0 , y = 0 ;
for ( int i = 0 ; i < N; i++)
{
x = 0 ;
for ( int j = 0 ; j < N; j++)
{
if (arr[i][j] == 'X' )
x += 1 ;
else
x = 0 ;
dp[i][j][ 0 ] = x;
}
}
for ( int i = 0 ; i < N; i++)
{
y = 0 ;
for ( int j = 0 ; j < N; j++)
{
if (arr[j][i] == 'X' )
y += 1 ;
else
y = 0 ;
dp[j][i][ 1 ] = y;
}
}
int maxval = 0 , val = 0 ;
for ( int i = 0 ; i < N; i++)
{
for ( int j = 0 ; j < N; j++)
{
val = Math.min(dp[i][j][ 0 ], dp[i][j][ 1 ]);
if (dp[i][j - val + 1 ][ 1 ] >= val
&& dp[i - val + 1 ][j][ 0 ] >= val)
maxside[i][j] = val;
else
maxside[i][j] = 0 ;
maxval = Math.max(maxval, maxside[i][j]);
}
}
return maxval;
}
public static void main (String[] args)
{
int mat[][] = {
{ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' },
{ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' },
{ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' },
};
System.out.println(maximumSubSquare(mat));
}
}
|
Python3
N = 6
def maximumSubSquare(arr):
dp = [[[ - 1 , - 1 ] for i in range ( 51 )]
for j in range ( 51 )]
maxside = [[ 0 for i in range ( 51 )]
for j in range ( 51 )]
x = 0
y = 0
for i in range (N):
x = 0
for j in range (N):
if (arr[i][j] = = 'X' ):
x + = 1
else :
x = 0
dp[i][j][ 0 ] = x
for i in range (N):
y = 0
for j in range (N):
if (arr[j][i] = = 'X' ):
y + = 1
else :
y = 0
dp[j][i][ 1 ] = y
maxval = 0
val = 0
for i in range (N):
for j in range (N):
val = min (dp[i][j][ 0 ],
dp[i][j][ 1 ])
if (dp[i][j - val + 1 ][ 1 ] > = val and
dp[i - val + 1 ][j][ 0 ] > = val):
maxside[i][j] = val
else :
maxside[i][j] = 0
maxval = max (maxval, maxside[i][j])
return maxval
mat = [ [ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' ],
[ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' ],
[ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' ] ]
print (maximumSubSquare(mat))
|
C#
using System;
public class GFG{
static int N = 6;
static int maximumSubSquare( int [,] arr)
{
int [,,] dp = new int [51,51,2];
int [,] maxside = new int [51,51];
for ( int i = 0; i < 51; i++)
{
for ( int j = 0; j < 51; j++)
{
maxside[i,j] = 10;
}
}
int x = 0, y = 0;
for ( int i = 0; i < N; i++)
{
x = 0;
for ( int j = 0; j < N; j++)
{
if (arr[i,j] == 'X' )
x += 1;
else
x = 0;
dp[i,j,0] = x;
}
}
for ( int i = 0; i < N; i++)
{
y = 0;
for ( int j = 0; j < N; j++)
{
if (arr[j,i] == 'X' )
y += 1;
else
y = 0;
dp[j,i,1] = y;
}
}
int maxval = 0, val = 0;
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < N; j++)
{
val = Math.Min(dp[i,j,0], dp[i,j,1]);
if (dp[i,j - val + 1,1] >= val
&& dp[i - val + 1,j,0] >= val)
maxside[i,j] = val;
else
maxside[i,j] = 0;
maxval = Math.Max(maxval, maxside[i,j]);
}
}
return maxval;
}
static public void Main (){
int [,] mat = {
{ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' },
{ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' },
{ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' },
{ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' },
};
Console.WriteLine(maximumSubSquare(mat));
}
}
|
Javascript
<script>
let N = 6;
function maximumSubSquare(arr)
{
let dp = new Array(51);
for (let i = 0; i < 51; i++)
{
dp[i] = new Array(51);
for (let j = 0; j < 51; j++)
{
dp[i][j] = new Array(2);
for (let k = 0; k < 2; k++)
{
dp[i][j][k] = 0;
}
}
}
let maxside = new Array(51);
for (let i = 0; i < 51; i++)
{
maxside[i] = new Array(51);
for (let j = 0; j < 51; j++)
{
maxside[i][j] = 10;
}
}
let x = 0, y = 0;
for (let i = 0; i < N; i++)
{
x = 0;
for (let j = 0; j < N; j++)
{
if (arr[i][j] == 'X' )
x += 1;
else
x = 0;
dp[i][j][0] = x;
}
}
for (let i = 0; i < N; i++)
{
y = 0;
for (let j = 0; j < N; j++)
{
if (arr[j][i] == 'X' )
y += 1;
else
y = 0;
dp[j][i][1] = y;
}
}
let maxval = 0, val = 0;
for (let i = 0; i < N; i++)
{
for (let j = 0; j < N; j++)
{
val = Math.min(dp[i][j][0], dp[i][j][1]);
if (dp[i][j - val + 1][1] >= val
&& dp[i - val + 1][j][0] >= val)
maxside[i][j] = val;
else
maxside[i][j] = 0;
maxval = Math.max(maxval, maxside[i][j]);
}
}
return maxval;
}
let mat=[[ 'X' , 'O' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'O' , 'X' , 'X' , 'O' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'O' , 'X' ],
[ 'O' , 'X' , 'X' , 'X' , 'X' , 'X' ],
[ 'X' , 'X' , 'X' , 'O' , 'X' , 'O' ],
[ 'O' , 'O' , 'X' , 'O' , 'O' , 'O' ]
];
document.write(maximumSubSquare(mat));
</script>
|
Time complexity: O(N2)
Auxiliary space: O(N2)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...