简体   繁体   中英

python find biggest free square in nested list

Ok, so I have to find the biggest "free square" in a grid where some spots are filled, for example, there's this grid:

###---
###---
###---
---### 
---### 
---### 

Where "-" is a filled spot and "#" is a free zone. This is done by filling a nested list: [[###---],[###---],...,[---###]] The inner lists are the vertical lines on the grid. So this grid could be filled in any way, and I'm supposed to find a way to 'calculate' the biggest possible square that can still be filled. In the above example, the output would be: 9. I'll give another example to make things clear:

########## 
#####----# 
##--#----# 
##--#----# 
##--#----# 
##--#----# 
#####----# 
########## 
-####----# 
########## 

The output here should be 16, wich is the square from (1,6) to (4,9) (counting from 0)

I hope someone could help me with this problem, thanks in advance! :)

This is quite a classic problem, which is nicely solved in the Dr. Dobb's Journal . Your available squares is just the true valued squares in the article.

In this particular case (limited to a square as you describe) you can do this.

First, consider a 'square' that is only one character: either - or # . It is trivial to see that the size of the square is just testing that one character as either 'taken' or not.

Now consider a 4x4 square:

--
--

or

[['-','-'],
 ['-','-']]

How do you calculate the max size? You take one element, say the upper left, and test it and its three neighbors if they are taken or not:

>>> sq=   [['-','-'],
...     ['-','-']]
>>> sq
[['-', '-'], ['-', '-']]
>>> if(all(sq[i][j]=='-' for i in (0,1) for j in (0,1))): print 4
... 
4

So generally, take a square and look at its neighbors. You can keep a running count in a matrix that is shaped the same as the target:

st='''\
########## 
#####----# 
##--#----# 
##--#----# 
##--#----# 
##--#----# 
#####----# 
########## 
-####----# 
########## '''

def max_size(mat, taken):
    """Find the largest X or a square not taken in the matrix `mat`."""
    nrows, ncols = len(mat), len(mat[0]) 
    assert nrows==ncols 
    dirs=(0,1),(1,0),(1,1) # right, down, right and down
    counts = [[0]*ncols for _ in range(nrows)]
    for i in reversed(range(nrows)):     # for each row
        assert len(mat[i]) == ncols      # matrix must be rectangular
        for j in reversed(range(ncols)): # for each element in the row
            if mat[i][j] != taken:
                if i < (nrows - 1) and j < (ncols - 1):
                    add=1+min(counts[i+x][j+y] for x,y in (dirs))
                else:
                    add=1      # edges 
                counts[i][j]=add        

    for line in counts: print(line)                               
    return max(c for rows in counts for c in rows)   # max X (or Y) number elements

table=[[c for c in s.strip()] for s in st.splitlines()]     

print (max_size(table,'#')**2)

Note that this function starts in the lower right corner and works backwards to the upper left corner and keeps a running total of the max square that could be at the vertex:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 4, 3, 2, 1, 0]
[0, 0, 2, 1, 0, 4, 3, 2, 1, 0]
[0, 0, 2, 1, 0, 4, 3, 2, 1, 0]
[0, 0, 2, 1, 0, 3, 3, 2, 1, 0]
[0, 0, 1, 1, 0, 2, 2, 2, 1, 0]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 1, 1, 1, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Then square the return for the answer of 16 (4x4). You can see that it would trivial to figure where each square would fit in this matrix; every one is calculated in counts and you would just add a tuple of (i,j) to the matrix counts or another one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM