算法笔记-扫雷游戏

529.扫雷游戏

LeetCode难度:中等

问题:

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

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

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

说明:

  LeetCode示例图:
img
思路:

  每次点击一个方块,如果不是地雷,则需要判断其本身与周围的格子状态,也就是说判断会逐渐往外扩散,直到遇到边界或者地雷。这个过程可以用深度递归来模拟。

  我们来一步步剖析规则:

  1.如果挖到地雷M,修改其为X,直接返回即可。

  2.如果click元素不是地雷M,则调用 turnOver() 这个方法,传入click坐标翻开空方块E:首先遍历click元素周围8个元素,跳过越界,计数周围地雷的数量,如果地雷计数cnt为0,则表示click挖到没有相邻地雷的方块,继续调用 turnOver() 方法,传入周围元素作为click坐标,递归地深度优先遍历。

  3.如果地雷计数cnt大于0(不可能小于0),则表示空方块E至少与一个地雷相邻,将其元素修改为地雷计数cnt即可表示相邻地雷的数量。

  4.无更多方块可揭露的含义就是在揭露方块的过程中跳过越界以及跳过非空方块

代码实现:

class Solution {
     
    //向被揭露点周围八格探索的增量(scX和scY元素一一对应)
    int[] scX = {
     -1, -1, -1, 0, 0, 1, 1, 1};
    int[] scY = {
     -1, 0, 1, -1, 1, -1, 0, 1};
    public char[][] updateBoard(char[][] board, int[] click) {
     
        //行x 列y
        int x = click[0], y = click[1];
        //规则1:挖到地雷直接结束;否则递归地挖出空方块
        if (board[x][y] == 'M')
            board[x][y] = 'X';
        else
            turnOver(board, x, y);
        return board;
    }
    //递归揭露未挖出方块E
    public void turnOver(char[][] board, int x, int y) {
     
        //统计相邻地雷数量
        int cnt = 0;
        for (int i = 0; i < 8; i++) {
     
            //周围八格坐标newX, newY
            int newX = x + scX[i];
            int newY = y + scY[i];
            //跳过越界
            if (newX < 0 || newX >= board.length || newY < 0 || newY >= board[0].length)
                continue;
            //地雷计数
            if (board[newX][newY] == 'M')
                cnt++;
        }
        //规则2:无相邻地雷,递归揭露相邻未挖出方块
        if (cnt == 0) {
     
            board[x][y] = 'B';
            for (int i = 0; i < 8; i++) {
     
                int newX = x + scX[i];
                int newY = y + scY[i];
                //跳过越界,跳过非空方块
                if (newX < 0 || newX >= board.length || newY < 0 || newY >= board[0].length || board[newX][newY] != 'E')
                    continue;
                //递归揭露每个空方块E
                turnOver(board, newX, newY);
            }
        } else {
      
        	//规则3:存在相邻地雷,空方块E修改为cnt
            //注意int -> char,需要强制转换
            board[x][y] = (char)(cnt + '0');
        }
    }
}

时间复杂度O(mn):最坏情况遍历board整个二维数组
空间复杂度O(mn):最坏情况递归栈装满board整个二维数组

你可能感兴趣的:(算法笔记,算法,递归法,java,leetcode)