算法-广度优先遍历-计算最短路径距离-双队列

题目要求

题目的题目基本上是这一题的升级版,

一个由 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一堆了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值