I need to find the largest square of 1's in a giant file full of 1's and 0's. I know i have to use dynamic programming. I am storing it in a 2D array. Any help with the algorithm to find the largest square would be great, thanks!
example input:
1 0 1 0 1 0
1 0 1 1 1 1
0 1 1 1 1 1
0 0 1 1 1 1
1 1 1 1 1 1
answer:
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
My code so far:
int Square (Sq[int x][int y]) {
if (Sq[x][y]) == 0) {
return 0;
}
else {
return 1+MIN( Sq(X-1,Y), Sq(X,Y-1), Sq(X-1,Y-1) );
}
}
(assuming values already entered into the array)
int main() {
int Sq[5][6]; //5,6 = bottom right conner
int X = Square(Sq[5][6]);
}
How do I go on from there?
Here is a sketch of the solution:
For each of the cells we will keep a counter of how big a square can be made using that cell as top left. Clearly all cells with 0 will have 0 as the count.
Start iterating from bottom right cell and go to bottom left, then go to one row up and repeat.
At each scan do this:
count=0
count=1
max_count
variable to keep track of the max count so far.At the end of traversing the matrix,
max_count
will have the desired value.Complexity is no more that the cost of traversal of the matrix.
This is how the matrix will look like after the traversal. Values in parentheses are the counts, i.e. biggest square that can be made using the cell as top left.
Implementation in Python
LSBRA(X,Y)
means "Largest Square with Bottom-Right At X,Y"Pseudocode:
(For edge cells, you can skip the MIN part and just return 1 if (x,y) is not 0.)
Work diagonally through the grid in "waves", like the following:
or alternatively, work through left-to-right, top-to-bottom, as long as you fill in edge cells.
That way you'll never run into a computation where you haven't previously computed the necessary data - so all of the
LSBRA()
"calls" are actually just table lookups of your previous computation results (hence the dynamic programming aspect).Why it works
In order to have a square with a bottom-right at X,Y - it must contain the overlapping squares of one less dimension that touch each of the other 3 corners. In other words, to have
you must also have...
As long as you have those 3 (each of the LSBRA checks) N-size squares plus the current square is also "occupied", you will have an (N+1)-size square.
Let input matrix is
M
: n x mT[i][j]
is DP matrix which contains largest square side with squares bottom right angle(i,j)
.General rule to fill the table:
The result square size is max value in
T
.Filling
T[i][0]
andT[0][j]
is trivial.I am not sure if this algo can be used for your huge file, but you don't need to store entire matrix
T
but only current and previous lines only.Following notes can help to undestand general idea:
OK, the most inefficient way but simple would be:
select first item. check if 1, if so you have a 1x1 square.
check one below and one to right, if 1, then check row 2 col 2, if 1, 2x2 square.
check row 3 col 1, col 2 and col 3, plus row 1 col 3, row 2 col 3, if 1, 3x3.
So basically you keep expanding the row and col together and check all the cells inside their boundaries. As soon as you hit a 0, it's broken, so you move along 1 point in a row, and start again.
At end of row, move to next row.
until the end.
You can probably see how those fit into while loops etc, and how
&&
s can be used to check for the 0s, and as you look at it, you'll perhaps also notice how it can be sped up. But as the other answer just mentioned, it does sound a little like homework so we'll leave the actual code up to you.Good luck!
The first algorithm that comes to my mind is:
I won't show you the implementation as its quite straightforward and your problem sounds like homework. Additionally there are likely much more efficient ways to do this, as this will become slow if the input was very large.
The key here is that you can keep track of the root of the area instead of the actual area, using dynamic programming.
The algorithm is as follow:
Store an 2D array of ints called max-square, where an element at index i,j represents the size of the square it's in with i,j being the bottom right corner. (if max[i,j] = 2, it means that index i,j is the bottom right corner of a square of size 2^2 = 4)
For each index i,j:
if at i,j the element is 0, then set max-square i,j to 0.
else:
Find the minimum of max-square[i - 1, j] and max-square[i, j - 1] and max-square[i - 1][j -1]. set max-square[i, j] to 1 + the minimum of the 3. Inductively, you'll end up filling in the max-square array. Find/or keep track of the maximum value in the process, return that value^2.
Take a look at these solutions people have proposed: https://leetcode.com/discuss/questions/oj/maximal-square?sort=votes