[英]Python Recursion Issue (Leetcode 542)
I think I misunderstand some important concepts in Python and it is not specific to the Leetcode problem.我想我误解了 Python 中的一些重要概念,它并不是特定于 Leetcode 问题。 I greatly appreciate for any help from who knows Python deeply.
我非常感谢深入了解 Python 的人提供的任何帮助。
The Leetcode 542 is that given a 2D array consisting of 0 and 1 only, and for each 1, find the shortest distance to reach 0. I have a dummy DFS solution: Leetcode 542是给定一个仅由 0 和 1 组成的二维数组,对于每个 1,找到到达 0 的最短距离。我有一个虚拟 DFS 解决方案:
class Solution:
def updateMatrix(self, matrix):
dists = []
for _ in range(len(matrix)):
dists.append([0]*len(matrix[0]))
for y in range(len(matrix)):
for x in range(len(matrix[0])):
if matrix[y][x] == 1:
self.min_dist = len(matrix)+len(matrix[0])
self.DFS(x, y, matrix, 0, set({}))
dists[y][x] = self.min_dist
return dists
def DFS(self, x, y, matrix, distance, visited):
if (x, y) in visited or (matrix[y][x] == 1 and distance > self.min_dist): return
if matrix[y][x] == 0:
print (x, y, "d:", distance)
print ('------')
self.min_dist = min(self.min_dist, distance)
return
print (x, y, distance)
visited.add((x, y))
if x > 0 and (x-1, y) not in visited:
self.DFS(x-1, y, matrix, distance+1, visited)
if y > 0 and (x, y-1) not in visited:
self.DFS(x, y-1, matrix, distance+1, visited)
if x < len(matrix[0])-1 and (x+1, y) not in visited:
self.DFS(x+1, y, matrix, distance+1, visited)
if y < len(matrix)-1 and (x, y+1) not in visited:
self.DFS(x, y+1, matrix, distance+1, visited)
Simply DFS until reaching 0. Every time we call DFS, distance + 1
.只需 DFS 直到达到 0。每次我们调用 DFS,
distance + 1
。 It looks good to me.对我来说看起来不错。 But a test case
input = [[1,0,0],[0,1,1],[1,1,1]]
gives me dist = [[1,0,0],[0,1,1],[1,2,3]]
.但是一个测试用例
input = [[1,0,0],[0,1,1],[1,1,1]]
给了我dist = [[1,0,0],[0,1,1],[1,2,3]]
。
If change matrix[y][x] == 1
to matrix[y][x] == 1 and x==2 and y==2
and run the above code, the output is如果将
matrix[y][x] == 1
更改为matrix[y][x] == 1 and x==2 and y==2
并运行上述代码,则 output 为
2 2 0
1 2 1
0 2 2
0 1 d: 3
------
1 1 2
0 1 d: 3
------
1 0 d: 3
------
2 1 3
2 0 d: 4
------
At (x,y)= (2,1) the initial distance is changed to 3. but the initial distance at (2,1) should be 1. My question is why it changes?在 (x,y)= (2,1) 处,初始距离更改为 3。但 (2,1) 处的初始距离应为 1。我的问题是它为什么会改变? Can anyone help me point out where I did wrong?
谁能帮我指出我做错了什么? Thanks!
谢谢!
You don't really need recursion for this.你真的不需要递归。 You can simply queue positions that need to update their neighbours and keep updating/queuing positions until no more updates are made:
您可以简单地将需要更新其邻居的位置排队并继续更新/排队位置,直到不再进行更新:
def getDistances(matrix):
rows,cols = len(matrix),len(matrix[0])
maxDist = rows*cols+1 # start 1's at maximum distance
result = [[maxDist*bit for bit in row] for row in matrix]
more = { (r,c) for r,row in enumerate(matrix)
for c,bit in enumerate(row) if bit == 0}
while more: # process queue starting with zero positions
r,c = more.pop()
newDist = result[r][c]+1 # neighbours are at distance+1 from here
for nr,nc in [(r,c+1),(r,c-1),(r+1,c),(r-1,c)]: # 4 directions
if nr not in range(rows): continue
if nc not in range(cols): continue
if newDist >= result[nr][nc]: continue
result[nr][nc] = newDist # reduce neighbour's distance
more.add((nr,nc)) # queue neighbour to cascade updates
return result
output: output:
m = [[0,0,0,0,0,1],
[0,1,1,0,0,0],
[1,1,1,1,0,1],
[1,1,1,1,1,0]]
for r in getDistances(m): print(r)
[0, 0, 0, 0, 0, 1]
[0, 1, 1, 0, 0, 0]
[1, 2, 2, 1, 0, 1]
[2, 3, 3, 2, 1, 0]
Been taking a look at this.一直在看这个。 It seems the problem is the way the
visited
set is modified.似乎问题在于修改
visited
集的方式。 I think it's being passed by reference which means by the time it tries to go (2,2) -> (2,1)
the set already contains the point (2,1)
, ie the preceding DFS paths have added all their points to it.我认为它是通过引用传递的,这意味着当它尝试 go
(2,2) -> (2,1)
该集合已经包含点(2,1)
,即前面的 DFS 路径已经添加了所有点给它。
I found this article explains "Pass By Reference in Python" well - https://realpython.com/python-pass-by-reference/ .我发现这篇文章很好地解释了“Python 中的引用传递” - https://realpython.com/python-pass-by-reference/ 。
I got your test case to pass by always passing down visited.copy()
, ie self.DFS(x-1, y, matrix, distance+1, visited.copy())
.我通过始终传递visited.copy
visited.copy()
即self.DFS(x-1, y, matrix, distance+1, visited.copy())
)) 使您的测试用例通过。 I'm not a Python expert and imagine there are cleaner ways to handle this though.我不是 Python 专家,但可以想象有更清洁的方法来处理这个问题。
First of all I want to point out that DFS, as well as BFS, is mainly used for searching in trees ;首先我要指出的是,DFS 和 BFS 一样,主要用于树中的搜索; indeed, you can think your matrix as a particular tree, but I wouldn't go that path for this task because you don't need to search but rather to keep track of some distance with respect to all of your neighbors, parents and children .
实际上,您可以将您的矩阵视为一棵特定的树,但我不会 go 执行此任务的路径,因为您不需要搜索,而是跟踪与所有邻居、父母和孩子的距离.
Moreover, with DFS you will need to traverse your matrix many times to find the minimum for every 1
s and that's very inefficient.此外,使用 DFS,您将需要多次遍历矩阵以找到每
1
秒的最小值,这是非常低效的。
Regarding your question, if you keep track of stack you're creating, you will get:关于您的问题,如果您跟踪正在创建的堆栈,您将获得:
2 2 0
1 2 1
0 2 2
0 1 d: 3
------
back to (0, 2), with distance = 2
(1, 2) already visited
back to (1, 2) with distance = 1
1 1 2
0 1 d: 3
------
back to (1, 1) with distance = 2
1 0 d: 3
------
back to (1, 1) with distance = 2
2 1 3
2 0 d: 4
Back to your task, since you're using python I would tackle this task by using numpy
, and look for 1
s and 0
s using np.where(matrix == 0)
.回到您的任务,因为您使用的是 python 我将使用 numpy 来解决此任务,并使用
numpy
np.where(matrix == 0)
查找1
s 和0
s。 Then it's just a matter of doing some calculus:那么这只是做一些微积分的问题:
import numpy as np
class Solution:
def update_matrix(self, matrix):
matrix = np.array(matrix)
x_ones, y_ones = np.where(matrix == 1)
x_zeros, y_zeros = np.where(matrix == 0)
for i in range(len(x_ones)):
temp = []
for j in range(len(x_zeros)):
temp.append(abs(x_ones[i] - x_zeros[j]) + abs(y_ones[i] - y_zeros[j]))
matrix[x_ones[i], y_ones[i]] = min(temp)
return matrix.tolist()
If you must not use external libraries, just proceed as follows:如果您不能使用外部库,请按照以下步骤操作:
class Solution:
def update_matrix(self, matrix):
x_ones, y_ones = [], []
x_zeros, y_zeros = [], []
# First scan to save coordinates
for i in range(len(matrix)):
for j in range(len(matrix[0])):
if matrix[i][j] == 1:
x_ones.append(i)
y_ones.append(j)
else:
x_zeros.append(i)
y_zeros.append(j)
for i in range(len(x_ones)):
temp = []
for j in range(len(x_zeros)):
temp.append(abs(x_ones[i] - x_zeros[j]) + abs(y_ones[i] - y_zeros[j]))
matrix[x_ones[i]][y_ones[i]] = min(temp)
return matrix
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.