学习方法与心得:迷宫最短路径问题
在解决豆包 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)的路径。 - 最少黑色格子数量:我们需要找到一条路径,从起点到终点,经过的黑色格子数量最少。
解决思路
这个问题可以使用 广度优先搜索(BFS) 来求解。BFS适合解决无权图的最短路径问题。我们可以将每个格子视为图中的一个节点,起点是 (1, 1),终点是 (n, m)。BFS在每次扩展时,尽量选择经过较少黑色格子的路径。
- 使用 队列 存储当前坐标和经过的黑色格子数。
- 在每一步移动时,更新到达每个格子的最少黑色格子数量。
- 最后返回到达终点
(n, m)时的最少黑色格子数。
BFS的状态表示
我们用一个二维数组 dist 来记录每个格子到起点的最少黑色格子数量。初始化时,将起点的黑色格子数设为 grid[0][0](即 0 或 1),然后进行BFS更新。
-
方向数组:
dx和dy数组分别表示上下左右四个方向的坐标变化。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。
-