Python 寻找到所有建筑物最短距离的优化算法
问题是在给定网格的情况下,找到一个0值点到所有建筑物的最短距离。你只能上下左右移动。您可能会遇到以下值: 0-空空间 1-建筑物 2-障碍物 我用Python编写的解决方案如下:Python 寻找到所有建筑物最短距离的优化算法,python,algorithm,breadth-first-search,Python,Algorithm,Breadth First Search,问题是在给定网格的情况下,找到一个0值点到所有建筑物的最短距离。你只能上下左右移动。您可能会遇到以下值: 0-空空间 1-建筑物 2-障碍物 我用Python编写的解决方案如下: import sys class Solution(object): def shortestDistance(self, grid): """ :type grid: List[List[int]] :rtype: int """
import sys
class Solution(object):
def shortestDistance(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
if grid is None:
return -1
tup = self.findPoints(grid)
buildings = tup[0]
zeroPoints = tup[1]
distances = []
for points in zeroPoints:
dist = self.bfs(grid, points, buildings)
distances += [dist]
return self.select(distances)
def findPoints(self, grid):
buildings = 0
zeroPoints = []
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 0:
zeroPoints += [[i,j]]
elif grid[i][j] == 1:
buildings += 1
return (buildings, zeroPoints)
def bfs(self, grid, root, targets):
hits, sumDist = 0, 0
targetsFound = []
while hits < targets:
q = []
q.append((root, 0))
found = False
visited = []
while(len(q) > 0):
tup = q.pop(0)
curr = tup[0]
dist = tup[1]
if grid[curr[0]][curr[1]] == 1 and curr not in targetsFound:
found = True
sumDist += dist
targetsFound += [curr]
break
if grid[curr[0]][curr[1]] == 0:
if (curr[0] - 1) >= 0 and grid[curr[0] -1][curr[1]] != 2 and [curr[0] - 1, curr[1]] not in visited:
q.append(([curr[0] - 1, curr[1]], dist + 1))
visited += [[curr[0] - 1, curr[1]]]
if (curr[0] + 1) < len(grid) and grid[curr[0] + 1][curr[1]] != 2 and [curr[0] + 1, curr[1]] not in visited:
q.append(([curr[0] + 1, curr[1]], dist + 1))
visited += [[curr[0] + 1, curr[1]]]
if (curr[1] - 1) >= 0 and grid[curr[0]][curr[1] - 1] != 2 and [curr[0], curr[1] - 1] not in visited:
q.append(([curr[0], curr[1] - 1], dist + 1))
visited += [[curr[0], curr[1] - 1]]
if (curr[1] + 1) < len(grid[0]) and grid[curr[0]][curr[1] + 1] != 2 and [curr[0], curr[1] + 1] not in visited:
q.append(([curr[0], curr[1] + 1], dist +1))
visited += [[curr[0], curr[1] + 1]]
if found:
hits += 1
else:
return - 1
return sumDist
def select(self, distances):
min = sys.maxsize
for dist in distances:
if dist < min and dist != -1:
min = dist
if min == sys.maxsize:
return -1
else:
return min
注意:更改visited和targetsFound可以提高效率,但不足以通过所有测试用例
更新:
通过将算法更改为从每个建筑而不是每个零点进行搜索,我能够在某些大输入上将算法改进96%,并通过所有测试用例。更新后的算法如下。谢谢尼瑟的建议
def shortestDistanceWalk(grid):
onePoints = findPointsWalk(grid)
for point in onePoints:
bfsWalk(grid, point)
shortestDistance = sys.maxsize
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] < 0 and shortestDistance > (grid[i][j] * -1):
shortestDistance = (grid[i][j] * -1)
if shortestDistance == sys.maxsize:
return -1
else:
return shortestDistance
def findPointsWalk(grid):
onePoints = []
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
onePoints += [[i,j]]
return onePoints
def bfsWalk(grid, root):
q = []
q.append((root, 0))
found = False
visited = set()
while(len(q) > 0):
tup = q.pop(0)
curr = tup[0]
dist = tup[1]
if grid[curr[0]][curr[1]] <= 0:
grid[curr[0]][curr[1]] += dist
if (curr[0] - 1) >= 0 and grid[curr[0] -1][curr[1]] <= 0 and (curr[0] - 1, curr[1]) not in visited:
q.append(([curr[0] - 1, curr[1]], dist - 1))
visited.add((curr[0] - 1, curr[1]))
if (curr[0] + 1) < len(grid) and grid[curr[0] + 1][curr[1]] <= 0 and (curr[0] + 1, curr[1]) not in visited:
q.append(([curr[0] + 1, curr[1]], dist - 1))
visited.add((curr[0] + 1, curr[1]))
if (curr[1] - 1) >= 0 and grid[curr[0]][curr[1] - 1] <= 0 and (curr[0], curr[1] - 1) not in visited:
q.append(([curr[0], curr[1] - 1], dist - 1))
visited.add((curr[0], curr[1] - 1))
if (curr[1] + 1) < len(grid[0]) and grid[curr[0]][curr[1] + 1] <= 0 and (curr[0], curr[1] + 1) not in visited:
q.append(([curr[0], curr[1] + 1], dist - 1))
visited.add((curr[0], curr[1] + 1))
for i in range(len(grid)):
for j in range(len(grid[0])):
if (i, j) not in visited:
grid[i][j] = 3
return
将targetsFound变量更改为。
使用该变量的原因是查找是否已访问某个单元格,并且列表中的查找速度较慢。集合支持快速查找O1,因此应该大大提高算法的性能
有关ON和O1含义的更多信息:将targetsFound变量更改为a。
使用该变量的原因是查找是否已访问某个单元格,并且列表中的查找速度较慢。集合支持快速查找O1,因此应该大大提高算法的性能
更多关于ON和O1的含义的信息:谢谢您的帮助,但仍然不足以通过所有测试用例。你能想出一个更强大的修剪方法吗?我认为你的方法可能不好,想象一下你有999个零分和1个建筑,你会做999个BFSE。在这种情况下,从大楼做一个BFS可以找到从每个零点到它的最短路径,效率会提高999倍,哈哈。也许你想通过某种方式比较建筑物/零点的数量,在某些情况下,翻转运行BFS的位置。只是一个想法,不确定是否有效。我想你是对的。在我这么做之前,我将修改算法,从每个建筑进行搜索,更新每个零处的距离,使其为最负。然后返回k个建筑搜索后的最小负距离,在无法到达所有建筑的点上存储3个。谢谢这有帮助,但仍然不足以通过所有测试用例。你能想出一个更强大的修剪方法吗?我认为你的方法可能不好,想象一下你有999个零分和1个建筑,你会做999个BFSE。在这种情况下,从大楼做一个BFS可以找到从每个零点到它的最短路径,效率会提高999倍,哈哈。也许你想通过某种方式比较建筑物/零点的数量,在某些情况下,翻转运行BFS的位置。只是一个想法,不确定是否有效。我想你是对的。在我这么做之前,我将修改算法,从每个建筑进行搜索,更新每个零处的距离,使其为最负。然后返回k个建筑搜索后的最小负距离,在无法到达所有建筑的点上存储3个。
def shortestDistanceWalk(grid):
onePoints = findPointsWalk(grid)
for point in onePoints:
bfsWalk(grid, point)
shortestDistance = sys.maxsize
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] < 0 and shortestDistance > (grid[i][j] * -1):
shortestDistance = (grid[i][j] * -1)
if shortestDistance == sys.maxsize:
return -1
else:
return shortestDistance
def findPointsWalk(grid):
onePoints = []
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
onePoints += [[i,j]]
return onePoints
def bfsWalk(grid, root):
q = []
q.append((root, 0))
found = False
visited = set()
while(len(q) > 0):
tup = q.pop(0)
curr = tup[0]
dist = tup[1]
if grid[curr[0]][curr[1]] <= 0:
grid[curr[0]][curr[1]] += dist
if (curr[0] - 1) >= 0 and grid[curr[0] -1][curr[1]] <= 0 and (curr[0] - 1, curr[1]) not in visited:
q.append(([curr[0] - 1, curr[1]], dist - 1))
visited.add((curr[0] - 1, curr[1]))
if (curr[0] + 1) < len(grid) and grid[curr[0] + 1][curr[1]] <= 0 and (curr[0] + 1, curr[1]) not in visited:
q.append(([curr[0] + 1, curr[1]], dist - 1))
visited.add((curr[0] + 1, curr[1]))
if (curr[1] - 1) >= 0 and grid[curr[0]][curr[1] - 1] <= 0 and (curr[0], curr[1] - 1) not in visited:
q.append(([curr[0], curr[1] - 1], dist - 1))
visited.add((curr[0], curr[1] - 1))
if (curr[1] + 1) < len(grid[0]) and grid[curr[0]][curr[1] + 1] <= 0 and (curr[0], curr[1] + 1) not in visited:
q.append(([curr[0], curr[1] + 1], dist - 1))
visited.add((curr[0], curr[1] + 1))
for i in range(len(grid)):
for j in range(len(grid[0])):
if (i, j) not in visited:
grid[i][j] = 3
return