我好像逃却逃不掉 | 豆包MarsCode AI刷题

82 阅读3分钟

184ba9f930fb58594571e4f84f300812.jpeg

题目速览

在一个 NxM 的竞技场迷宫中,你的任务是找出在迷宫中,所有”危险位置”的数量。 "危险位置”定义为:如果站在该位置上,无论采取什么移动策略,都无法到达出口。

竞技场中包含以下几种元素:
. :表示普通地板,可以自由移动到上下左右相邻的格子(不可以走斜线)
O:表示出口
U:表示向上的传送器,踩上去会被强制传送到上方的格子
D:表示向下的传送器,踩上去会被强制传送到下方的格子
L:表示向左的传送器,踩上去会被强制传送到左方的格子
R:表示向右的传送器,踩上去会被强制传送到右方的格子

注意,如果被传送出了竞技场之外,则算作死亡。

解题思路

  1. 题目要求我们寻找不能到达出口的位置,假设我们正向寻找,设想一下每一个位置有四个可能的方向,它的下一个可能位置也有四个可能的方向... ,这直接爆炸,因此,我们只能反向寻找。
  2. 反向寻找:我们从出口开始遍历,采用BFS广度优先搜索,如果不能访问到的位置,那他一定是危险位置,明确了这个思路,接下来,开始详细的代码设计

代码设计

  1. 首先,BFS广度优先搜索,需要搭配队列实现,同时,我们需要记录某个位置是是否被访问,需要一个二维数组,代码如下:
boolean[][] visited = new boolean[N][M];
Queue<int[]> queue = new LinkedList<>();
  1. 将所有出口的位置先保存在队列中,同时,记录对应位置为已访问,代码如下:
for (int i = 0; i < N; i++) {
   for (int j = 0; j < M; j++) {
       if (data[i][j] == 'O') {
          queue.add(new int[] { i, j });
          visited[i][j] = true;
       }
    }
}
  1. BFS反向搜索
  • 构建循环,循环的结束条件为队列是否为空
  • 从队列中取出要访问的位置,判断可能前进的四个位置,在判断可能前进的位置时,要确保可能前进位置没有被访问过,保证BFS始终向前遍历,避免向后遍历,导致死循环
  • 接下来,我们要弄清,如何判断前进的位置是否可行
    1. 如果前进是普通地板或者是出口,一定可以
    2. 如果前进的位置是有方向的,假设想向左前进,那么左边位置的前进方向必须必须是向右;这个很好理解,我们现在是从出口反向寻找,如果前进方向和位置指定前进方向相同,那我们正向遍历时,这两个位置一定不联通,因此,前进方向和位置指定前进方向相反。同理,其他方向也是相同的
  • 如果前进的位置可行,我们将位置保存到队列中,并记录该位置已访问,代码如下:
while (!queue.isEmpty()) {
    int[] current = queue.poll();
    int x = current[0];
    int y = current[1];
    if (x >= 1 && (data[x-1][y] == 'D' || data[x-1][y] == '.') && !visited[x-1][y]) {
        queue.add(new int[] { x - 1, y });
        visited[x-1][y] = true;
    }
    if (y >= 1 && (data[x][y-1] == 'R' || data[x][y-1] == '.') && !visited[x][y-1]) {
        queue.add(new int[]{x, y - 1});
        visited[x][y-1] = true;
    }
    if (x <= data.length - 2 && (data[x+1][y] == 'U' || data[x+1][y] == '.') && !visited[x+1][y]) {
        queue.add(new int[]{x + 1, y});
        visited[x+1][y] = true;
    }
    if (y <= data[0].length - 2 && (data[x][y+1] == 'L' || data[x][y+1] == '.') && !visited[x][y+1]) {
       queue.add(new int[]{x, y + 1});
       visited[x][y+1] = true;
    }
}
  1. 统计未被访问到的位置,返回结果
int dangerCount = 0;
for (int i = 0; i < N; i++) {
   for (int j = 0; j < M; j++) {
      if (!visited[i][j]) {
         dangerCount++;
      }
   }
}

总结

BFS和DFS是图这一类题中核心思路,合理的使用队列和栈可以好的解决问题。