【dfs】B013_扫雷游戏(dfs | bfs)

一、题目描述

给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,
'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,
数字('1''8')表示有多少地雷与这块已挖出的方块相邻,
'X' 则表示一个已挖出的地雷。

现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),
根据以下规则,返回相应位置被点击后对应的面板:

如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。
如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),
并且所有和其相邻的方块都应该被递归地揭露。
如果一个至少与一个地雷相邻的空方块('E')被挖出,
修改它为数字('1''8'),表示相邻地雷的数量。
如果在此次点击中,若无更多方块可被揭露,则返回面板。

二、题解

方法一:dfs

题目的信息比较多,不妨把他们拆分:

  • ‘M’ :没有挖出的地雷
  • ‘X’ :被挖出的地雷,遇到 X 代表游戏结束。
  • ‘E’ :一个未知的方块。
  • ‘B’ :一个八个方向都确认没有地雷的方块。
  • click[0]:游戏第 1 步的横坐标。
  • click[1]:游戏第 1 步的纵坐标。

算法

  • 如果当前位置不是地雷 M,则暂时标记为 B,然后判断当前位置的 8 个方向外1步的距离内是否地雷 M,有则将其标记用地雷的个数 countM 覆盖标记 B。
  • 否则,将地雷位置标记为 X 即可,因为涂抹说明只有一个地雷 M。
int m, n;
private static int[][] dir = {
  {-1, 0}, {1, 0},
  {0, -1}, {0, 1},
  {-1, -1},{-1, 1},
  {1, -1}, {1, 1},
};
public char[][] updateBoard(char[][] grid, int[] click) {
  m = grid.length;
  n = grid[0].length;
  dfs(grid, click[0], click[1]);
  return grid;
}
//深搜
private void dfs(char[][] grid, int x, int y) {
  if (!inArea(x, y))
      return;
  if (grid[x][y] == 'M') {
      grid[x][y] = 'X';
  }else if (grid[x][y] == 'E') {
    grid[x][y] = 'B';
    int countM = countM(grid, x, y);
    if (countM > 0) {
      grid[x][y] = (char) (countM + '0');
    }else {
      for (int i = 0; i < 8; i++) {
        int newX = x + dir[i][0];
        int newY = y + dir[i][1];
        dfs(grid, newX, newY);
      }
    }
  }
}
//统计8个方向的地雷数量
private int countM(char[][] grid, int x, int y) {
  int count = 0;
  for (int i = 0; i < 8; i++) {
    int newX = x + dir[i][0];
    int newY = y + dir[i][1];
    if (inArea(newX, newY) && grid[newX][newY] == 'M') {
      count++;
    }
  }
  return count;
}
private boolean inArea(int x, int y) {
  return x >= 0 && x < m && y >= 0 && y < n;
}

复杂度分析

  • 时间复杂度: O ( m × n ) O(m × n)
  • 空间复杂度: O ( m × n ) O(m × n)

方法二:bfs

不管使用什么方式解决这个问题,其本质都是在遍历整个网格,只是遍历方式不一样,但主体逻辑是相同的。

int m, n;
private static int[][] dir = {
	{-1, 0}, {1, 0},
	{0, -1}, {0, 1},
	{-1, -1},{-1, 1},
	{1, -1}, {1, 1},
};
public char[][] updateBoard(char[][] grid, int[] click) {
  m = grid.length;
  n = grid[0].length;
  Queue<Pos> queue = new LinkedList<>();
  queue.add(new Pos(click[0], click[1]));

  while (!queue.isEmpty()) {
    Pos pos = queue.poll();
    if (grid[pos.x][pos.y] == 'E') {
        grid[pos.x][pos.y] = 'B';
        int count = countM(grid, pos.x, pos.y);
        if (count > 0) {
        	grid[pos.x][pos.y] = ((char) (count + '0'));
        } else {
            for (int i = 0; i < 8; i++) {
                int newX = pos.x + dir[i][0];
                int newY = pos.y + dir[i][1];
                if (inArea(newX, newY)) {
                    queue.add(new Pos(newX, newY));
                }
            }
        }
    } else if (grid[pos.x][pos.y] == 'M')
        grid[pos.x][pos.y] = 'X';
  }
  return grid;
}

private boolean inArea(int x, int y) {
  return x >= 0 && x < m && y >= 0 && y < n;
}
private int countM(char[][] grid, int x, int y) {
  int count = 0;
  for (int i = 0; i < 8; i++) {
      int newX = x + dir[i][0];
      int newY = y + dir[i][1];
      if (inArea(newX, newY) && grid[newX][newY] == 'M') {
          count++;
      }
  }
  return count;
}

class Pos {
  int x, y;
  public Pos(int _x, int _y) {
      x = _x;
      y = _y;
  }
}

复杂度分析

  • 时间复杂度: O ( m × n ) O(m × n)
  • 空间复杂度: O ( m × n ) O(m × n)
发布了495 篇原创文章 · 获赞 105 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104783764
今日推荐