题目要求
题目的题目基本上是这一题的升级版,
一个由 0(通路)和 1(墙壁)组成的二维迷宫中,是否存在一条从起点到终点的有效路径。我只能上下左右移动,不能穿墙,也不能走出迷宫。如果两个点之间有通路,则输出最短的通路距离,如果没有,则输出-1.
一开始的思路
一开始的思路是这样的,初始化一个step变量来管理目前的路径长度,一旦抵达终点即返回。每次一个节点被访问完四周可行节点后step自动+1。
def bfs(x_start, y_start, x_end, y_end, maze, q, n, m):
q.append((x_start, y_start))
maze[x_start][y_start] = 1 # 改动,加入队列之后立刻标记为已访问
step = 0
while q:
x, y = q.popleft()
# maze[x][y] = 1 # 改动前,这会导致一个位置被多次访问
if x == x_end and y == y_end:
return step
else:
wait_list = [(x, y-1), (x, y+1), (x-1, y), (x+1, y)]
for candidate in wait_list:
next_x = candidate[0]
next_y = candidate[1]
if in_maze(next_x, next_y, n, m) and maze[next_x][next_y] != 1:
q.append(candidate)
maze[next_x][next_y] = 1
step += 1
return False
存在的问题
提交代码之后发现步数远远超过答案,经过排查后,我发现原本的代码逻辑并不合理。在这种step的更新方式下,就算两个不同路线的路径步数一样,由于step的更新方式是只要弹出一个就+1, 所以会step会多加很多次,它实际上记录的是已处理的节点数量,而非从起点到当前位置的实际最短距离。

改进方法
注意到之前对step的更新方式的错误设计源自于对更新逻辑含义的具体含义, 从代码的含义入手分析,我重新设计了一套更新step的方式:
def bfs(x_start, y_start, x_end, y_end, maze, n, m):
q_now_epoch = deque()
q_next_epoch = deque()
q_now_epoch.append((x_start, y_start))
maze[x_start][y_start] = 1 # 改动,加入队列之后立刻标记为已访问
step = 0
while q_now_epoch or q_next_epoch:
if len(q_now_epoch) == 0:
step += 1
q_now_epoch = q_next_epoch.copy()
q_next_epoch.clear()
x, y = q_now_epoch.popleft()
# maze[x][y] = 1 # 改动前,这会导致一个位置被多次访问
if x == x_end and y == y_end:
return step
else:
wait_list = [(x, y-1), (x, y+1), (x-1, y), (x+1, y)]
for candidate in wait_list:
next_x = candidate[0]
next_y = candidate[1]
if in_maze(next_x, next_y, n, m) and maze[next_x][next_y] != 1:
q_next_epoch.append(candidate)
maze[next_x][next_y] = 1
return False
核心思路是将原本的队列拆分为两个队列,一个是当前轮队列(q_now_epoch),其包含的节点都具有相同的已走步长。另一个是(q_next_epoch),包含下一轮要走的节点,步长将会是当前轮队列的已走步长+1, 节点的弹出在当前轮队列进行,新加入的节点入下一轮队列,一旦当前轮队列为空,step+1并且将q_next_epoch全部加入当前轮队列,重复此过程直到抵达终点或者两个队列都为空

感悟
思路越简明,代码实现逻辑也同样的越简明。但简明的思路可不是免费的午餐,得深入理解题目用意,代码逻辑的实际语义,才能设计出简明的,解决问题的思路和代码。不然就是缝缝补补,bug一堆了。
1136

被折叠的 条评论
为什么被折叠?



