附上题目连接:
https://leetcode-cn.com/problems/minesweeper/
题解见注释:
class Solution {
//以[0,0]为节点,对应的周围8个节点的delta相对位置的变化
int[] deltaY = {-1,0,1,-1,1,-1,0,1};
int[] deltaX = {-1,-1,-1,0,0,1,1,1};
public char[][] updateBoard(char[][] board, int[] click) {
//对应row
int x = click[0];
//对应column
int y = click[1];
//如果碰到地雷,修改'M'为'X',直接返回,对应提示中的第1点
if(board[x][y]=='M'){
board[x][y]='X';
}else if(board[x][y]=='E'){
//如果是待挖的方块,分两种情况分别对应提示中的第2点和第3点
//上下左右,对角线,递归判断周边的'E'
dfs(board,x,y);
}
return board;
}
//x代表column,y代表row
private void dfs(char[][] board, int x,int y){
//如果在格子外部,小于最小值,或者大于等于格子长度 跳出dfs
//或者是所判断的元素不是'E',例如,遇到了数字,或者是'B',或者雷,都不用继续递归。
if(x < 0 || x >= board.length || y < 0 || y >= board[0].length || board[x][y]!='E'){
return;
}
//递归的过程中,要确定当前的方块中放什么字母
//这需要根据方块四周8个格子中有没有雷来决定
int numOfMines = calculateMines(board,x,y);
//如果没有雷,则是空白的Blank
if(numOfMines == 0){
board[x][y] = 'B';
//继续递归上下左右,对角线8个格子
for(int i = 0; i < deltaX.length ; i ++){
dfs(board,x+deltaX[i],y+deltaY[i]);
}
}else{
//如果有雷,则显示数字
board[x][y] = (char)('0'+numOfMines);
}
}
//检查row = x, column = y 对应的格子周围8个空格中有几个雷。
private int calculateMines(char[][] board,int x, int y){
int mines = 0;
int rowLength = board.length;
int columnLength = board[0].length;
for(int i = 0 ; i < deltaX.length ; i ++){
int column= y+deltaY[i];
int row = x+deltaX[i];
//超出8个格子的边界直接跳过,注意此处容易把上面dfs递归终止条件惯性带入导致出错
if(column < 0 || column >= columnLength || row < 0 || row >= rowLength){
continue;
}
//统计出雷的数量
if(board[row][column]=='M') {
mines++;
};
}
return mines;
}
}
刚开始没有想明白[0,3]对应的格子为什么是'E'而不是'1',后来仔细思考了一下,对应于题目中的第二条,因为dfs的过程中,如果碰到了数字就不会继续递归了,那么dfs的路径就无法经过[0,3]节点。
如果对测试的数据做一些修改,增加一行{'E','E','E','E','E'},看到原来位置上[1,3]对应的'E'变成了'1'
LeetCode对应题解:
https://leetcode-cn.com/problems/minesweeper/solution/dfsqiu-jie-sao-lei-yi-ji-03wei-shi-yao-b-sut6/