【LeetCode】529. 扫雷游戏

题目链接

529. 扫雷游戏

题目描述

让我们一起来玩扫雷游戏!

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

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

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

解题思路

典型的BFS或者DFS。

1.DFS

给定初始二维数组和起点,返回修改后的二维数组。

  • 若起点处是雷,即 ‘M’,直接将其修改为 'X',游戏结束;
  • 若起点处是空,即 ‘E’,则从起点开始向 8 邻域中的空地搜索,判断8邻域是否有炸弹,如果有就把该坐标的值修改为炸弹的个数并退出,如果没有则把该坐标的值按照题目的要求修改为“B”。继续对其8邻域搜索即可

写DFS相关题目的时候,只要把边界条件,递归条件判断好就行了,这也是比较难的地方。

2.BFS

BFS就是利用队列来实现,依葫芦画瓢就OK了

AC代码

1.DFS

class Solution {

    int dir[][] = {{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};

    public char[][] updateBoard(char[][] board, int[] click) {
        int x = click[0];
        int y = click[1];
        if(board[x][y] == 'M'){
            board[x][y] = 'X';
            return board;
        }
        else dfs(board,x,y);
        return board;
    }

    void dfs(char[][] board,int x,int y){
        if(x<0||x>=board.length||y<0||y>=board[0].length) return;
        if(board[x][y] != 'E') return;
        int cnt = 0;
        for(int i = 0; i < 8; i++){
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
            if(xx<0||xx>=board.length||yy<0||yy>=board[0].length) continue;
            if(board[xx][yy] == 'M') cnt++;
        }
        if(cnt>0){
            board[x][y] = (char)(cnt+'0');
            return;
        }else
        {
            board[x][y] = 'B';
        }

        for(int i = 0; i < 8; i++){
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
            dfs(board,xx,yy);
        }
    }
}

2.BFS

代码中viewer数组是关键,一开始超时了就是因为把很多重复判断过的点又加入队列中,
    DFS可能不需要viewer数组用于记录某点是否遍历过
    但是BFS是一定需要的!!!!!
class Solution {
    int dir[][] = {{0,1},{0,-1},{-1,0},{1,0},{-1,-1},{1,1},{1,-1},{-1,1}};
    Queue<int []> queue = new LinkedList<>();
    public char[][] updateBoard(char[][] board, int[] click) {
        int x = click[0];
        int y = click[1];
        // 1. 若起点是雷,游戏结束,直接修改 board 并返回。
        if(board[x][y] == 'M'){
            board[x][y] = 'X';
            return board;
        }else{
            // 2. 若起点是空地,则将起点入队,从起点开始向 8 邻域的空地进行宽度优先搜索。
            int buf[] = {x,y};
            queue.offer(buf);
            //viewe数组用于记录该坐标点是否以及遍历过!
            int viewer[][] = new int[board.length][board[0].length];
            while(!queue.isEmpty()){
                // 判断空地 (temp[0], temp[1]) 周围是否有雷
                int temp[] = queue.poll();
                int cnt = 0;
                for(int i = 0; i < 8; i++){
                    int x1 = temp[0] + dir[i][0];
                    int y1 = temp[1] + dir[i][1];
                    if(x1<0||x1>=board.length||y1<0||y1>=board[0].length) continue;
                    if(board[x1][y1] == 'M') cnt++;
                }
                //若空地(temp[0],temp[1])周围有雷,则将该位置修改为雷数;否则将该位置更新为‘B’,并将其8邻域中的空地入队,继续进行bfs搜索。
                if(cnt>0){
                    board[temp[0]][temp[1]] = (char)('0' + cnt);
                }else{
                    board[temp[0]][temp[1]] = 'B';
                    for(int i = 0; i < 8; i++){
                        int x1 = temp[0] + dir[i][0];
                        int y1 = temp[1] + dir[i][1];
                        if(x1<0||x1>=board.length||y1<0||y1>=board[0].length||board[x1][y1] != 'E' || viewer[x1][y1] == 1) continue;
                        viewer[x1][y1] = 1;
                        queue.offer(new int[]{x1,y1});
                    }
                }
            }
            return board;
        }
    }
}
原文地址:https://www.cnblogs.com/XDU-Lakers/p/13536689.html