青训营刷题算法学习心得5| 豆包MarsCode AI 刷题

129 阅读3分钟

学习方法与心得:迷宫最短路径问题

在解决豆包 MarsCode AI 刷题题库中的迷宫最短路径问题的时候,我遇到了一个问题,那就是如何在规定时间内找到一条含最少黑色块的迷宫路径。我的思想是将所有的解依次遍历,求出最短的黑色路径。但是时间复杂度一下就达到了NP级。在确认代码逻辑没有问题的情况下我自己的ide都没有跑出来。时间复杂度过高,我开始考虑如和设计剪枝,但是过于复杂使我停止思考转而向豆包 MarsCode AI 提问。在MarsCode AI的帮助下,我很快学会了如和设计BFS并进行剪枝控制。我自己的代码时间复杂度为o(2^n),而AI给出的解决方法时间复杂度仅为o(m*n),使我大受震撼。

/**
 * 小S在一个n×mn×m的网格迷宫中,初始位置在左上角(1,1),
 * 目标是到达右下角(n,m)。每个格子可以是黑色(表示为1)或者白色(表示为0)。
 * 他希望在移动过程中经过的黑色格子尽可能少。移动时可以向上、下、左、右四个方向移动,
 * 但不能走出迷宫的边界。请你帮小S计算从起点到终点所需经过的最少黑色格子的数量。
 */

这是一个迷宫最短路径问题,我们需要计算从迷宫的左上角 (1, 1) 到右下角 (n, m) 的最少黑色格子的数量。迷宫的每个格子可以是黑色(1)或者白色(0)。我们可以向上、下、左、右四个方向移动,但不能走出迷宫的边界。

这个问题的关键是:

  1. 路径选择:每次移动时,我们尽量选择经过较少的黑色格子(1)的路径。
  2. 最少黑色格子数量:我们需要找到一条路径,从起点到终点,经过的黑色格子数量最少。

解决思路

这个问题可以使用 广度优先搜索(BFS) 来求解。BFS适合解决无权图的最短路径问题。我们可以将每个格子视为图中的一个节点,起点是 (1, 1),终点是 (n, m)。BFS在每次扩展时,尽量选择经过较少黑色格子的路径。

  • 使用 队列 存储当前坐标和经过的黑色格子数。
  • 在每一步移动时,更新到达每个格子的最少黑色格子数量。
  • 最后返回到达终点 (n, m) 时的最少黑色格子数。

BFS的状态表示

我们用一个二维数组 dist 来记录每个格子到起点的最少黑色格子数量。初始化时,将起点的黑色格子数设为 grid[0][0](即 0 或 1),然后进行BFS更新。

  • 方向数组

    • dxdy 数组分别表示上下左右四个方向的坐标变化。dx = {-1, 1, 0, 0}dy = {0, 0, -1, 1} 分别对应上、下、左、右四个方向。
  • dist 数组

    • dist[i][j] 表示从起点 (0, 0) 到达坐标 (i, j) 时所经过的最少黑色格子数。初始化时,所有值都设为 Integer.MAX_VALUE(表示尚未访问)。起点 (0, 0) 的初始值是 grid[0][0]
  • BFS过程

    • 使用队列 queue 存储当前正在访问的坐标,每次从队列中取出一个坐标,检查其四个方向的邻接点,计算经过该点的黑色格子数量,并更新邻接点的 dist 值。
    • 如果通过某个邻接点的路径比之前记录的路径更少黑色格子,则将该点加入队列,并更新 dist 值。
  • 返回结果

    • 最终,返回右下角 (n-1, m-1) 位置的最少黑色格子数。如果无法到达该位置(即 dist[n-1][m-1] 仍为 Integer.MAX_VALUE),则返回 -1