A question on dynamic programming leetcode problem 221 - python

I'm a beginner in Python. The following is my code for leetcode 221 (Maximal Square), it can only pass more than 30 test samples. It fails at the matrix: M=[["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]].
def maximalSquare(matrix):
colleng=len(matrix)
rowleng=len(matrix[0])
maxsqlst=[]
dp=[[0]*rowleng]*colleng
for i in range(colleng):
for j in range(rowleng):
if matrix[i][j]=='1':
if i==0 or j==0:
print('A',i,j,dp)
dp[i][j]=1
print('B',i,j,dp)
else:
dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
print(i,j,dp)
maxsqlst.append(max(dp[i]))
return max(maxsqlst)**2
By inserting some print() command, I find that it goes wrong when i=j=0,
A 0 0 [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
B 0 0 [[1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0]].
Why does it make the first colume to be 1 instead of just dp[0][0]?

TL;DR: Change your definition of dp from
dp = [[0]*rowleng]*colleng
to
dp = [[0 for i in range(rowleng)] for j in range(colleng)]
Why? In the first, you're creating a 2D list of references to the same list; in the second, you're creating a 2D list of references to unique lists.
(Technically, you could rewrite the 2nd lind as dp = [[0]*rowleng for j in range(colleng)] and get the same result.)
All that to say, when you declare dp to be a list of references to the same list, then when you change dp[0][0], it "also changes" dp[i][0] for all 0 < i < len(dp) -- because it's all the same list being referred to.
See e.g. List of lists changes reflected across sublists unexpectedly for more info.

In your function, you call this line:
dp[i][j]=1
This sets the item of i and j to 1, and if you notice the section where its called:
if matrix[i][j]=='1':
if i==0 or j==0:
You will notice that both of those conditions are true in the cases you get 1, as this value is overriding whatever other values you've had, at least from what I see.
Remember that you are comparing with an or and not an and, so if either i or j were zero, not both necessarily, you will end up overriding the value, especially in locations where your matrix is equal to 1 (Here, your first column is all ones).

Related

Just start to learn 2D array in Python. Why both codes generate different outputs just by changing place of col=[ ]

Code that works perfectly:
rows, cols = (4,2)
arr=[]
for i in range(rows):
col = []
for j in range(cols):
col.append(0)
arr.append(col)
print(arr)
Output:
[[0, 0], [0, 0], [0, 0], [0, 0]]
Alternative implementation:
rows, cols = (4,2)
arr=[]
col = []
for i in range(rows):
for j in range(cols):
col.append(0)
arr.append(col)
print(arr)
Output:
[[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]
Why both codes generate different outputs just by changing place of col where an empty list is assigned to it. I have tried to get concept with trace table but got confused.
This is one of the classic Python blunders. Your entire second program contains EXACTLY two lists. There's one bound to col, and one bound to arr, and the one bound to arr contains multiple references to the first list. It does not contain 4 different lists, it contains 4 links to the SAME list.
To do what you want, you need to create a NEW empty list in each iteration, as you have done in the first example.

python 2-dimensional list changes an entire column at once? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 1 year ago.
So given a m*n matrix represented as columns, I'm supposed to increment one index at a time to fill a specified amount of row and column, say if I'm supposed to increment (2,0), it'll ONLY increment (2,0).
So I wrote this code:
for i in range(row):
for j in range(col):
print("X")
print(matrix)
content = matrix[i][j]
matrix[i][j]=content+1
print("matrix ({},{}) = {}".format(i,j,matrix[i][j]))
I added several prints to debug the code, and on the first index it outputs:
X
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
matrix (0,0) = 1
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
it's supposed to increment (0,0) to 1 so it's supposed to look like this:
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
but as you can see....it increments an entire row at once... I don't know why it happened, did I miss something?
The problem is in the way you created the matrix, which you didn't show us. You probably did something like this:
matrix = [[0]*col]*row
What's not obvious from this is that this creates ONE list with 'col' zeros, and then creates 'row' references to that one list. There are not 'row' separate lists. When you change one of the lists, you'll see that in all of the rows. You need to do something like this:
matrix = [ [0]*row for _ in col ]
Or, as #Jan suggested, use numpy.

Trying to create and alter grid, but assigning values to specific index in nested list is unexpectedly duplicated to other nested lists

(Python 3.9) I'm trying to solve a percolation problem/assignment, and just to start, I'm creating an n-by-n grid. While the grid looks correct on creation, when I try to alter a specific value inside the grid (in a nested list), it's assigning that value to every sublist, rather than only the list I'm referencing with it's index.
Here's the class and relevant bits:
class Percolation:
"""Create an n-by-n grid, with all sites initially blocked."""
def __init__(self, n):
self.grid = self.create_grid(n)
def create_grid(self, n):
""" Create n-by-n grid with default 0 (blocked) values."""
grid = []
# Create x, rows.
values = [0 for _ in range(n)]
# Create y, columns.
for _ in range(n):
grid.append(values)
return grid
def show_grid(self):
for row in self.grid:
print(row)
size = 5
perc = Percolation(size)
# I chose 8 and 5 arbitrarily to test this issue so they're easy to spot.
perc.grid[0][2] = 8
perc.grid[1][1] = 5
perc.show_grid()
show_grid() is then showing me all sublists are changed.
>>>
[0, 5, 8, 0, 0]
[0, 5, 8, 0, 0]
[0, 5, 8, 0, 0]
[0, 5, 8, 0, 0]
[0, 5, 8, 0, 0]
While what I was expecting is this:
>>>
[0, 0, 8, 0, 0]
[0, 5, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
Am I making the mistake when I create the grid by appending "values" multiple times in a loop? Or am I incorrectly referencing indexes? I thought maybe at first show_grid() was accidentally printing the same row over and over, but printing self.grid directly still shows duplicate values across all sublists, regardless of n or how I assign values.
What I do see is that when I change only a value in the main list, I do get what I expect.
perc.grid[2] = [0, 0, 8, 0, 0]
perc.show_grid()
>>>
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 8, 0, 0]
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
How do I properly change values in these nested lists in this case? What is actually happening when I'm setting perc.grid[0][2] = 8?
In python when you create a list and assign it to multiple places, it is the same list, not a new list with the same values. So when you create the list values and append it to grid, each nested list is actually the same list.
One way you can avoid this problem is by copying the list using an index of the entire list [:] like:
grid.append(values[:])

Apending a list in a list multiple times retaining the ability to change a specific element in python

I want to create a grid with a variable number of rows and columns. What I have done to achieve this is this
BaseRow = []
for j in range (0, columns):
BaseRow.append(0)
Grid = []
for j in range (0, rows):
Grid.append(BaseRow)
So all seems fine until now, I print the rows in order with this piece of code
for i in range (1, rows+1):
print Grid[rows-i]
and a grid that looks something like this
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
is printed. Thing is, afterwards, I want to change a specific element. But when I do,
Grid[0][0] = 1
and print again, instead of just changing the rightmost down most 0 to a 1, the whole column changes, so it becomes
[1, 0, 0]
[1, 0, 0]
[1, 0, 0]
I suspect it sees that Grid is taking from BaseRow, so it changes BaseRow, and then the Grid takes the rows from BaseRow and just puts that value everywhere. I suspect .append might not be what I am looking for, but for all the research I have done I have not managed to find something else to use. If I understand correctly, .extend will not add it as a list but as individual numbers. What should I change, or how should I structure this?
Please excuse my limited knowledge, I just started programming in python half a week ago. Thanks for your help!
BaseRow = []
for j in range (0, columns):
BaseRow.append(0)
Grid = []
for j in range (0, rows):
Grid.append(BaseRow)
When you do this, the same instance of BaseRow is appended to Grid multiple times. So, if you change even row in Grid, the effect will be on all rows, as it is basically the same instance of list in all rows.
If you want a copy of BaseRow to be appended to Grid, use the below code:
for j in range(0, rows):
Grid.append(BaseRow[:])
You could also use list comprehension:
Grid = [[0 for j in range(0, columns)] for i in range(0, rows)]
Output for Columns = 3 and rows = 4:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Output after setting Grid[0][0] = 1:
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
If you ask me, I would any day use List comprehension because it's so clean and easy:
columns, rows = 3, 3
lst = [[0 for j in range(columns)] for i in range(rows)] # List of List with 3 Columns and 3 Rows
lst[0][0] = 1 # modifying a member
print (lst) # Print the result
# Result: [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
I personally prefer list comprehension but your code needs just little changes and it will serve you well. You append list and to that list you append elements:
matrix = []
for i in range(3):
matrix.append([])
for j in range(4):
matrix[-1].append(0)
print(matrix)
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
matrix[0][0] = 1
print(matrix)
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

iterator in for loop of list and matrix in Python [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
I hope to set up a matrix/list through for loop but I observed different results between 1D list and 2D list of the same method. I know this is a stupid way to create a list through for loop but could anyone give me a hint what caused the difference please?
m = [[0] * 4] * 4
print m
m[0] = range(4)
for i in range(4):
m[i][0] = i
print m
And the result is:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
[[0, 1, 2, 3], [3, 0, 0, 0], [3, 0, 0, 0], [3, 0, 0, 0]]
I was expecting to be [[0, 1, 2, 3], [1, 0, 0, 0], [2, 0, 0, 0], [3, 0, 0, 0]].
However it worked find in 1D list as below
tmp = [0,0,0,0]
for i in range(4):
tmp[i] = i
print tmp
It printed [0,1,2,3] as I expected.
Change the first line to get:
#m = [[0] * 4] * 4
m = [([0] * 4) for _ in range(4)]
print m
m[0] = range(4)
for i in range(4):
m[i][0] = i
print m
What happened before was that you were creating four copies of the same list. Each copy looks to the same memory spaces. Python does this to conserve memory. So each time you write to one of the lists, you are in fact writing to all of them, and because the last value you write is 3, that's the value you get in all of the lists.
When you are doing m = [[0] * 4] * 4, you are creating a 2D matrix of all zeros. In other words, a list of four [0, 0, 0, 0] lists. Now, with m[0] = range(4), you are setting the first inner list to be [0,1,2,3]. Now when you do,
for i in range(4):
m[i][0] = i
you are expecting for each inner lists first element to be changed. This is one of python's quicks creep in. Object reference. When you initially create the 2D list, you are essentially referencing one list from each of the four indices. Then you replace m[0] to a separate list here: m[0] = range(4). However, all there indices refer to the same list object [0, 0, 0, 0]. And when the loop eventually finishes, value of i is 3 and that is assigned to the first element of the list. And since in index 1, 2 and 3 of m was referencing that list, all three show up as same - [3, 0, 0, 0]. Hope this helps.

Categories

Resources