Let's play the minesweeper game (Wikipedia),online game)!
You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine,'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine.
Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the board after revealing this position according to the following rules:
Example 1:
Input:
[['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'M', 'E', 'E'],
['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'E', 'E', 'E']]
Click : [3,0]
Output:
[['B', '1', 'E', '1', 'B'],
['B', '1', 'M', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']]
Explanation:
Example 2:
Input:
[['B', '1', 'E', '1', 'B'],
['B', '1', 'M', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']]
Click : [1,2]
Output:
[['B', '1', 'E', '1', 'B'],
['B', '1', 'X', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']]
Explanation:
Note:
玩过扫雷游戏的同学应该熟悉扫雷的规则,这题的目标在于模拟扫雷游戏,它给了一块已经完成一部分操作的扫雷面板,并且输入了下一步点击的位置。要求输出执行这次点击后面板的最新状态。
其中M表示隐藏的雷,X表示被点开的雷。E表示未被点开的空格,B表示被点开的空格,数字1到8表示距离该格子一圈一共有几个雷。
当玩家点击了格子后,一共有三种情况
这是一道典型的通过广搜或是深搜解决的题目。广搜即以雷区为中心,每次向外搜索一圈,深搜则是搜索到全是雷区为止。广搜代码如下:
public char[][] updateBoard(char[][] board, int[] click) {
char clickValue = board[click[0]][click[1]];
if (clickValue == 'M') {
board[click[0]][click[1]] = 'X';
} else if (clickValue == 'E') {
//广度优先遍历
Queue<int[]> queue = new LinkedList<>();
queue.offer(click);
//8个方向
int[][] directions = new int[][]{
{0, 1},
{0, -1},
{-1, 0},
{1, 0},
{-1, -1},
{-1, 1},
{1, 1},
{1,-1}
};
while (!queue.isEmpty()) {
int[] tmpClick = queue.poll();
int countOfMine = 0;
List<int[]> emptyCells = new ArrayList<>();
for (int\[] direction : directions) {
int rowIndex = direction[0] + tmpClick[0];
int columnIndex = direction[1] + tmpClick[1];
if (rowIndex < 0 || rowIndex >= board.length || columnIndex < 0 || columnIndex >= board[0].length) {
continue;
}
if (board[rowIndex][columnIndex] == 'M') {
countOfMine++;
} else if (board[rowIndex][columnIndex] == 'E') {
emptyCells.add(new int[]{rowIndex, columnIndex});
}
}
if (countOfMine == 0) {
board[tmpClick[0]][tmpClick[1]] = 'B';
//防止重复遍历,先将其置为B
for (int[] emptyCell : emptyCells) {
board[emptyCell[0]][emptyCell[1]] = 'B';
}
queue.addAll(emptyCells);
} else {
board[tmpClick[0]][tmpClick[1]] = (char)('0' + countOfMine);
}
}
}
return board;
}
深搜代码如下:
public char[][] updateBoard2(char[][] board, int[] click) {
int m = board.length, n = board[0].length;
int row = click[0], col = click[1];
if (board[row][col] == 'M') { // Mine
board[row][col] = 'X';
}
else { // Empty
// Get number of mines first. int count = 0;
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0) continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue;
if (board[r][c] == 'M' || board[r][c] == 'X') count++;
}
}
if (count > 0) { // If it is not a 'B', stop further DFS.
board[row][col] = (char)(count + '0');
}
else { // Continue DFS to adjacent cells.
//递归的进行深度优先遍历 board[row][col] = 'B';
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0) continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue;
if (board[r][c] == 'E') updateBoard(board, new int[] {r, c});
}
}
}
}
return board;
}