我想我误解了 Python 中的一些重要概念,它不是特定于 Leetcode 问题的。我非常感谢深入了解 Python 的人提供的任何帮助。
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)
简单的 DFS 直到达到 0。每次我们调用 DFS 时,distance + 1
。对我来说看起来不错。但是测试用例 input = [[1,0,0],[0,1,1],[1,1,1]]
给了我 dist = [[1,0,0],[0,1,1],[1,2,3]]
。
如果将matrix[y][x] == 1
改为matrix[y][x] == 1 and x==2 and y==2
并运行上面的代码,输出为
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
------
在 (x,y)= (2,1) 处,初始距离更改为 3。但 (2,1) 处的初始距离应为 1。我的问题是为什么会更改?谁能帮我指出我做错了什么?谢谢!
答案 0 :(得分:1)
你真的不需要递归。您可以简单地将需要更新其邻居的位置排队,并继续更新/排队位置,直到不再进行更新:
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
输出:
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]
答案 1 :(得分:1)
一直在看这个。问题似乎是修改 visited
集的方式。我认为它是通过引用传递的,这意味着当它尝试去 (2,2) -> (2,1)
时,集合已经包含点 (2,1)
,即前面的 DFS 路径已将其所有点添加到其中。
我发现这篇文章很好地解释了“Python 中的引用传递” - https://realpython.com/python-pass-by-reference/。
我让你的测试用例总是向下传递visited.copy()
,即self.DFS(x-1, y, matrix, distance+1, visited.copy())
。我不是 Python 专家,但我想有更简洁的方法来处理这个问题。
答案 2 :(得分:1)
首先我想指出,DFS和BFS一样,主要用于树中搜索;实际上,您可以将您的矩阵视为一棵特定的树,但我不会为此任务走这条路,因为您不需要搜索,而是保持与尊重您所有的邻居、父母和孩子。
此外,使用 DFS,您将需要多次遍历矩阵才能找到每个 1
的最小值,这非常低效。
关于你的问题,如果你跟踪你正在创建的堆栈,你会得到:
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
回到您的任务,因为您使用的是 python,我将使用 numpy
来处理此任务,并使用 1
查找 0
和 np.where(matrix == 0)
。那么这只是做一些微积分的问题:
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()
如果您一定不能使用外部库,请按以下步骤操作:
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